/**
 * tracking - A modern approach for Computer Vision on the web.
 * @author Eduardo Lundgren <edu@rdo.io>
 * @version v1.1.3
 * @link http://trackingjs.com
 * @license BSD
 */
var tracking = {}
;(function (window, undefined) {
	window.tracking = window.tracking || {}

	/**
	 * Inherit the prototype methods from one constructor into another.
	 *
	 * Usage:
	 * <pre>
	 * function ParentClass(a, b) { }
	 * ParentClass.prototype.foo = function(a) { }
	 *
	 * function ChildClass(a, b, c) {
	 *   tracking.base(this, a, b);
	 * }
	 * tracking.inherits(ChildClass, ParentClass);
	 *
	 * var child = new ChildClass('a', 'b', 'c');
	 * child.foo();
	 * </pre>
	 *
	 * @param {Function} childCtor Child class.
	 * @param {Function} parentCtor Parent class.
	 */
	tracking.inherits = function (childCtor, parentCtor) {
		function TempCtor() {}
		TempCtor.prototype = parentCtor.prototype
		childCtor.superClass_ = parentCtor.prototype
		childCtor.prototype = new TempCtor()
		childCtor.prototype.constructor = childCtor

		/**
		 * Calls superclass constructor/method.
		 *
		 * This function is only available if you use tracking.inherits to express
		 * inheritance relationships between classes.
		 *
		 * @param {!object} me Should always be "this".
		 * @param {string} methodName The method name to call. Calling superclass
		 *     constructor can be done with the special string 'constructor'.
		 * @param {...*} var_args The arguments to pass to superclass
		 *     method/constructor.
		 * @return {*} The return value of the superclass method/constructor.
		 */
		childCtor.base = function (me, methodName) {
			var args = Array.prototype.slice.call(arguments, 2)
			return parentCtor.prototype[methodName].apply(me, args)
		}
	}

	/**
	 * Captures the user camera when tracking a video element and set its source
	 * to the camera stream.
	 * @param {HTMLVideoElement} element Canvas element to track.
	 * @param {object} opt_options Optional configuration to the tracker.
	 */
	tracking.initUserMedia_ = function (element, opt_options) {
		window.navigator.mediaDevices
			.getUserMedia({
				video: true,
				audio: opt_options && opt_options.audio ? true : false,
			})
			.then(function (stream) {
				element.srcObject = stream
			})
			.catch(function (err) {
				throw Error('Cannot capture user camera.')
			})
	}

	/**
	 * Tests whether the object is a dom node.
	 * @param {object} o Object to be tested.
	 * @return {boolean} True if the object is a dom node.
	 */
	tracking.isNode = function (o) {
		return o.nodeType || this.isWindow(o)
	}

	/**
	 * Tests whether the object is the `window` object.
	 * @param {object} o Object to be tested.
	 * @return {boolean} True if the object is the `window` object.
	 */
	tracking.isWindow = function (o) {
		return !!(o && o.alert && o.document)
	}

	/**
	 * Selects a dom node from a CSS3 selector using `document.querySelector`.
	 * @param {string} selector
	 * @param {object} opt_element The root element for the query. When not
	 *     specified `document` is used as root element.
	 * @return {HTMLElement} The first dom element that matches to the selector.
	 *     If not found, returns `null`.
	 */
	tracking.one = function (selector, opt_element) {
		if (this.isNode(selector)) {
			return selector
		}
		return (opt_element || document).querySelector(selector)
	}

	/**
	 * Tracks a canvas, image or video element based on the specified `tracker`
	 * instance. This method extract the pixel information of the input element
	 * to pass to the `tracker` instance. When tracking a video, the
	 * `tracker.track(pixels, width, height)` will be in a
	 * `requestAnimationFrame` loop in order to track all video frames.
	 *
	 * Example:
	 * var tracker = new tracking.ColorTracker();
	 *
	 * tracking.track('#video', tracker);
	 * or
	 * tracking.track('#video', tracker, { camera: true });
	 *
	 * tracker.on('track', function(event) {
	 *   // console.log(event.data[0].x, event.data[0].y)
	 * });
	 *
	 * @param {HTMLElement} element The element to track, canvas, image or
	 *     video.
	 * @param {tracking.Tracker} tracker The tracker instance used to track the
	 *     element.
	 * @param {object} opt_options Optional configuration to the tracker.
	 */
	tracking.track = function (element, tracker, opt_options) {
		element = tracking.one(element)
		if (!element) {
			throw new Error(
				'Element not found, try a different element or selector.'
			)
		}
		if (!tracker) {
			throw new Error(
				'Tracker not specified, try `tracking.track(element, new tracking.FaceTracker())`.'
			)
		}

		switch (element.nodeName.toLowerCase()) {
			case 'canvas':
				return this.trackCanvas_(element, tracker, opt_options)
			case 'img':
				return this.trackImg_(element, tracker, opt_options)
			case 'video':
				if (opt_options) {
					if (opt_options.camera) {
						this.initUserMedia_(element, opt_options)
					}
				}
				return this.trackVideo_(element, tracker, opt_options)
			default:
				throw new Error(
					'Element not supported, try in a canvas, img, or video.'
				)
		}
	}

	/**
	 * Tracks a canvas element based on the specified `tracker` instance and
	 * returns a `TrackerTask` for this track.
	 * @param {HTMLCanvasElement} element Canvas element to track.
	 * @param {tracking.Tracker} tracker The tracker instance used to track the
	 *     element.
	 * @param {object} opt_options Optional configuration to the tracker.
	 * @return {tracking.TrackerTask}
	 * @private
	 */
	tracking.trackCanvas_ = function (element, tracker) {
		var self = this
		var task = new tracking.TrackerTask(tracker)
		task.on('run', function () {
			self.trackCanvasInternal_(element, tracker)
		})
		return task.run()
	}

	/**
	 * Tracks a canvas element based on the specified `tracker` instance. This
	 * method extract the pixel information of the input element to pass to the
	 * `tracker` instance.
	 * @param {HTMLCanvasElement} element Canvas element to track.
	 * @param {tracking.Tracker} tracker The tracker instance used to track the
	 *     element.
	 * @param {object} opt_options Optional configuration to the tracker.
	 * @private
	 */
	tracking.trackCanvasInternal_ = function (element, tracker) {
		var width = element.width
		var height = element.height
		var context = element.getContext('2d')
		var imageData = context.getImageData(0, 0, width, height)
		tracker.track(imageData.data, width, height)
	}

	/**
	 * Tracks a image element based on the specified `tracker` instance. This
	 * method extract the pixel information of the input element to pass to the
	 * `tracker` instance.
	 * @param {HTMLImageElement} element Canvas element to track.
	 * @param {tracking.Tracker} tracker The tracker instance used to track the
	 *     element.
	 * @param {object} opt_options Optional configuration to the tracker.
	 * @private
	 */
	tracking.trackImg_ = function (element, tracker) {
		var width = element.width
		var height = element.height
		var canvas = document.createElement('canvas')

		canvas.width = width
		canvas.height = height

		var task = new tracking.TrackerTask(tracker)
		task.on('run', function () {
			tracking.Canvas.loadImage(
				canvas,
				element.src,
				0,
				0,
				width,
				height,
				function () {
					tracking.trackCanvasInternal_(canvas, tracker)
				}
			)
		})
		return task.run()
	}

	/**
	 * Tracks a video element based on the specified `tracker` instance. This
	 * method extract the pixel information of the input element to pass to the
	 * `tracker` instance. The `tracker.track(pixels, width, height)` will be in
	 * a `requestAnimationFrame` loop in order to track all video frames.
	 * @param {HTMLVideoElement} element Canvas element to track.
	 * @param {tracking.Tracker} tracker The tracker instance used to track the
	 *     element.
	 * @param {object} opt_options Optional configuration to the tracker.
	 * @private
	 */
	tracking.trackVideo_ = function (element, tracker) {
		var canvas = document.createElement('canvas')
		var context = canvas.getContext('2d')
		var width
		var height

		var resizeCanvas_ = function () {
			width = element.offsetWidth
			height = element.offsetHeight
			canvas.width = width
			canvas.height = height
		}
		resizeCanvas_()
		element.addEventListener('resize', resizeCanvas_)

		var requestId
		var requestAnimationFrame_ = function () {
			requestId = window.requestAnimationFrame(function () {
				if (element.readyState === element.HAVE_ENOUGH_DATA) {
					try {
						// Firefox v~30.0 gets confused with the video readyState firing an
						// erroneous HAVE_ENOUGH_DATA just before HAVE_CURRENT_DATA state,
						// hence keep trying to read it until resolved.
						context.drawImage(element, 0, 0, width, height)
					} catch (err) {}
					tracking.trackCanvasInternal_(canvas, tracker)
				}
				requestAnimationFrame_()
			})
		}

		var task = new tracking.TrackerTask(tracker)
		task.on('stop', function () {
			window.cancelAnimationFrame(requestId)
		})
		task.on('run', function () {
			requestAnimationFrame_()
		})
		return task.run()
	}

	// Browser polyfills
	//===================

	if (!window.URL) {
		window.URL =
			window.URL || window.webkitURL || window.msURL || window.oURL
	}

	if (!navigator.getUserMedia) {
		navigator.getUserMedia =
			navigator.getUserMedia ||
			navigator.webkitGetUserMedia ||
			navigator.mozGetUserMedia ||
			navigator.msGetUserMedia
	}
})(window)
;(function () {
	/**
	 * EventEmitter utility.
	 * @constructor
	 */
	tracking.EventEmitter = function () {}

	/**
	 * Holds event listeners scoped by event type.
	 * @type {object}
	 * @private
	 */
	tracking.EventEmitter.prototype.events_ = null

	/**
	 * Adds a listener to the end of the listeners array for the specified event.
	 * @param {string} event
	 * @param {function} listener
	 * @return {object} Returns emitter, so calls can be chained.
	 */
	tracking.EventEmitter.prototype.addListener = function (event, listener) {
		if (typeof listener !== 'function') {
			throw new TypeError('Listener must be a function')
		}
		if (!this.events_) {
			this.events_ = {}
		}

		this.emit('newListener', event, listener)

		if (!this.events_[event]) {
			this.events_[event] = []
		}

		this.events_[event].push(listener)

		return this
	}

	/**
	 * Returns an array of listeners for the specified event.
	 * @param {string} event
	 * @return {array} Array of listeners.
	 */
	tracking.EventEmitter.prototype.listeners = function (event) {
		return this.events_ && this.events_[event]
	}

	/**
	 * Execute each of the listeners in order with the supplied arguments.
	 * @param {string} event
	 * @param {*} opt_args [arg1], [arg2], [...]
	 * @return {boolean} Returns true if event had listeners, false otherwise.
	 */
	tracking.EventEmitter.prototype.emit = function (event) {
		var listeners = this.listeners(event)
		if (listeners) {
			var args = Array.prototype.slice.call(arguments, 1)
			for (var i = 0; i < listeners.length; i++) {
				if (listeners[i]) {
					listeners[i].apply(this, args)
				}
			}
			return true
		}
		return false
	}

	/**
	 * Adds a listener to the end of the listeners array for the specified event.
	 * @param {string} event
	 * @param {function} listener
	 * @return {object} Returns emitter, so calls can be chained.
	 */
	tracking.EventEmitter.prototype.on =
		tracking.EventEmitter.prototype.addListener

	/**
	 * Adds a one time listener for the event. This listener is invoked only the
	 * next time the event is fired, after which it is removed.
	 * @param {string} event
	 * @param {function} listener
	 * @return {object} Returns emitter, so calls can be chained.
	 */
	tracking.EventEmitter.prototype.once = function (event, listener) {
		var self = this
		self.on(event, function handlerInternal() {
			self.removeListener(event, handlerInternal)
			listener.apply(this, arguments)
		})
	}

	/**
	 * Removes all listeners, or those of the specified event. It's not a good
	 * idea to remove listeners that were added elsewhere in the code,
	 * especially when it's on an emitter that you didn't create.
	 * @param {string} event
	 * @return {object} Returns emitter, so calls can be chained.
	 */
	tracking.EventEmitter.prototype.removeAllListeners = function (opt_event) {
		if (!this.events_) {
			return this
		}
		if (opt_event) {
			delete this.events_[opt_event]
		} else {
			delete this.events_
		}
		return this
	}

	/**
	 * Remove a listener from the listener array for the specified event.
	 * Caution: changes array indices in the listener array behind the listener.
	 * @param {string} event
	 * @param {function} listener
	 * @return {object} Returns emitter, so calls can be chained.
	 */
	tracking.EventEmitter.prototype.removeListener = function (
		event,
		listener
	) {
		if (typeof listener !== 'function') {
			throw new TypeError('Listener must be a function')
		}
		if (!this.events_) {
			return this
		}

		var listeners = this.listeners(event)
		if (Array.isArray(listeners)) {
			var i = listeners.indexOf(listener)
			if (i < 0) {
				return this
			}
			listeners.splice(i, 1)
		}

		return this
	}

	/**
	 * By default EventEmitters will print a warning if more than 10 listeners
	 * are added for a particular event. This is a useful default which helps
	 * finding memory leaks. Obviously not all Emitters should be limited to 10.
	 * This function allows that to be increased. Set to zero for unlimited.
	 * @param {number} n The maximum number of listeners.
	 */
	tracking.EventEmitter.prototype.setMaxListeners = function () {
		throw new Error('Not implemented')
	}
})()
;(function () {
	/**
	 * Canvas utility.
	 * @static
	 * @constructor
	 */
	tracking.Canvas = {}

	/**
	 * Loads an image source into the canvas.
	 * @param {HTMLCanvasElement} canvas The canvas dom element.
	 * @param {string} src The image source.
	 * @param {number} x The canvas horizontal coordinate to load the image.
	 * @param {number} y The canvas vertical coordinate to load the image.
	 * @param {number} width The image width.
	 * @param {number} height The image height.
	 * @param {function} opt_callback Callback that fires when the image is loaded
	 *     into the canvas.
	 * @static
	 */
	tracking.Canvas.loadImage = function (
		canvas,
		src,
		x,
		y,
		width,
		height,
		opt_callback
	) {
		var instance = this
		var img = new window.Image()
		img.crossOrigin = '*'
		img.onload = function () {
			var context = canvas.getContext('2d')
			canvas.width = width
			canvas.height = height
			context.drawImage(img, x, y, width, height)
			if (opt_callback) {
				opt_callback.call(instance)
			}
			img = null
		}
		img.src = src
	}
})()
;(function () {
	/**
	 * DisjointSet utility with path compression. Some applications involve
	 * grouping n distinct objects into a collection of disjoint sets. Two
	 * important operations are then finding which set a given object belongs to
	 * and uniting the two sets. A disjoint set data structure maintains a
	 * collection S={ S1 , S2 ,..., Sk } of disjoint dynamic sets. Each set is
	 * identified by a representative, which usually is a member in the set.
	 * @static
	 * @constructor
	 */
	tracking.DisjointSet = function (length) {
		if (length === undefined) {
			throw new Error('DisjointSet length not specified.')
		}
		this.length = length
		this.parent = new Uint32Array(length)
		for (var i = 0; i < length; i++) {
			this.parent[i] = i
		}
	}

	/**
	 * Holds the length of the internal set.
	 * @type {number}
	 */
	tracking.DisjointSet.prototype.length = null

	/**
	 * Holds the set containing the representative values.
	 * @type {Array.<number>}
	 */
	tracking.DisjointSet.prototype.parent = null

	/**
	 * Finds a pointer to the representative of the set containing i.
	 * @param {number} i
	 * @return {number} The representative set of i.
	 */
	tracking.DisjointSet.prototype.find = function (i) {
		if (this.parent[i] === i) {
			return i
		} else {
			return (this.parent[i] = this.find(this.parent[i]))
		}
	}

	/**
	 * Unites two dynamic sets containing objects i and j, say Si and Sj, into
	 * a new set that Si ∪ Sj, assuming that Si ∩ Sj = ∅;
	 * @param {number} i
	 * @param {number} j
	 */
	tracking.DisjointSet.prototype.union = function (i, j) {
		var iRepresentative = this.find(i)
		var jRepresentative = this.find(j)
		this.parent[iRepresentative] = jRepresentative
	}
})()
;(function () {
	/**
	 * Image utility.
	 * @static
	 * @constructor
	 */
	tracking.Image = {}

	/**
	 * Computes gaussian blur. Adapted from
	 * https://github.com/kig/canvasfilters.
	 * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
	 * @param {number} width The image width.
	 * @param {number} height The image height.
	 * @param {number} diameter Gaussian blur diameter, must be greater than 1.
	 * @return {array} The edge pixels in a linear [r,g,b,a,...] array.
	 */
	tracking.Image.blur = function (pixels, width, height, diameter) {
		diameter = Math.abs(diameter)
		if (diameter <= 1) {
			throw new Error('Diameter should be greater than 1.')
		}
		var radius = diameter / 2
		var len = Math.ceil(diameter) + (1 - (Math.ceil(diameter) % 2))
		var weights = new Float32Array(len)
		var rho = (radius + 0.5) / 3
		var rhoSq = rho * rho
		var gaussianFactor = 1 / Math.sqrt(2 * Math.PI * rhoSq)
		var rhoFactor = -1 / (2 * rho * rho)
		var wsum = 0
		var middle = Math.floor(len / 2)
		for (var i = 0; i < len; i++) {
			var x = i - middle
			var gx = gaussianFactor * Math.exp(x * x * rhoFactor)
			weights[i] = gx
			wsum += gx
		}
		for (var j = 0; j < weights.length; j++) {
			weights[j] /= wsum
		}
		return this.separableConvolve(
			pixels,
			width,
			height,
			weights,
			weights,
			false
		)
	}

	/**
	 * Computes the integral image for summed, squared, rotated and sobel pixels.
	 * @param {array} pixels The pixels in a linear [r,g,b,a,...] array to loop
	 *     through.
	 * @param {number} width The image width.
	 * @param {number} height The image height.
	 * @param {array} opt_integralImage Empty array of size `width * height` to
	 *     be filled with the integral image values. If not specified compute sum
	 *     values will be skipped.
	 * @param {array} opt_integralImageSquare Empty array of size `width *
	 *     height` to be filled with the integral image squared values. If not
	 *     specified compute squared values will be skipped.
	 * @param {array} opt_tiltedIntegralImage Empty array of size `width *
	 *     height` to be filled with the rotated integral image values. If not
	 *     specified compute sum values will be skipped.
	 * @param {array} opt_integralImageSobel Empty array of size `width *
	 *     height` to be filled with the integral image of sobel values. If not
	 *     specified compute sobel filtering will be skipped.
	 * @static
	 */
	tracking.Image.computeIntegralImage = function (
		pixels,
		width,
		height,
		opt_integralImage,
		opt_integralImageSquare,
		opt_tiltedIntegralImage,
		opt_integralImageSobel
	) {
		if (arguments.length < 4) {
			throw new Error(
				'You should specify at least one output array in the order: sum, square, tilted, sobel.'
			)
		}
		var pixelsSobel
		if (opt_integralImageSobel) {
			pixelsSobel = tracking.Image.sobel(pixels, width, height)
		}
		for (var i = 0; i < height; i++) {
			for (var j = 0; j < width; j++) {
				var w = i * width * 4 + j * 4
				var pixel = ~~(
					pixels[w] * 0.299 +
					pixels[w + 1] * 0.587 +
					pixels[w + 2] * 0.114
				)
				if (opt_integralImage) {
					this.computePixelValueSAT_(
						opt_integralImage,
						width,
						i,
						j,
						pixel
					)
				}
				if (opt_integralImageSquare) {
					this.computePixelValueSAT_(
						opt_integralImageSquare,
						width,
						i,
						j,
						pixel * pixel
					)
				}
				if (opt_tiltedIntegralImage) {
					var w1 = w - width * 4
					var pixelAbove = ~~(
						pixels[w1] * 0.299 +
						pixels[w1 + 1] * 0.587 +
						pixels[w1 + 2] * 0.114
					)
					this.computePixelValueRSAT_(
						opt_tiltedIntegralImage,
						width,
						i,
						j,
						pixel,
						pixelAbove || 0
					)
				}
				if (opt_integralImageSobel) {
					this.computePixelValueSAT_(
						opt_integralImageSobel,
						width,
						i,
						j,
						pixelsSobel[w]
					)
				}
			}
		}
	}

	/**
	 * Helper method to compute the rotated summed area table (RSAT) by the
	 * formula:
	 *
	 * RSAT(x, y) = RSAT(x-1, y-1) + RSAT(x+1, y-1) - RSAT(x, y-2) + I(x, y) + I(x, y-1)
	 *
	 * @param {number} width The image width.
	 * @param {array} RSAT Empty array of size `width * height` to be filled with
	 *     the integral image values. If not specified compute sum values will be
	 *     skipped.
	 * @param {number} i Vertical position of the pixel to be evaluated.
	 * @param {number} j Horizontal position of the pixel to be evaluated.
	 * @param {number} pixel Pixel value to be added to the integral image.
	 * @static
	 * @private
	 */
	tracking.Image.computePixelValueRSAT_ = function (
		RSAT,
		width,
		i,
		j,
		pixel,
		pixelAbove
	) {
		var w = i * width + j
		RSAT[w] =
			(RSAT[w - width - 1] || 0) +
			(RSAT[w - width + 1] || 0) -
			(RSAT[w - width - width] || 0) +
			pixel +
			pixelAbove
	}

	/**
	 * Helper method to compute the summed area table (SAT) by the formula:
	 *
	 * SAT(x, y) = SAT(x, y-1) + SAT(x-1, y) + I(x, y) - SAT(x-1, y-1)
	 *
	 * @param {number} width The image width.
	 * @param {array} SAT Empty array of size `width * height` to be filled with
	 *     the integral image values. If not specified compute sum values will be
	 *     skipped.
	 * @param {number} i Vertical position of the pixel to be evaluated.
	 * @param {number} j Horizontal position of the pixel to be evaluated.
	 * @param {number} pixel Pixel value to be added to the integral image.
	 * @static
	 * @private
	 */
	tracking.Image.computePixelValueSAT_ = function (SAT, width, i, j, pixel) {
		var w = i * width + j
		SAT[w] =
			(SAT[w - width] || 0) +
			(SAT[w - 1] || 0) +
			pixel -
			(SAT[w - width - 1] || 0)
	}

	/**
	 * Converts a color from a colorspace based on an RGB color model to a
	 * grayscale representation of its luminance. The coefficients represent the
	 * measured intensity perception of typical trichromat humans, in
	 * particular, human vision is most sensitive to green and least sensitive
	 * to blue.
	 * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
	 * @param {number} width The image width.
	 * @param {number} height The image height.
	 * @param {boolean} fillRGBA If the result should fill all RGBA values with the gray scale
	 *  values, instead of returning a single value per pixel.
	 * @param {Uint8ClampedArray} The grayscale pixels in a linear array ([p,p,p,a,...] if fillRGBA
	 *  is true and [p1, p2, p3, ...] if fillRGBA is false).
	 * @static
	 */
	tracking.Image.grayscale = function (pixels, width, height, fillRGBA) {
		var gray = new Uint8ClampedArray(
			fillRGBA ? pixels.length : pixels.length >> 2
		)
		var p = 0
		var w = 0
		for (var i = 0; i < height; i++) {
			for (var j = 0; j < width; j++) {
				var value =
					pixels[w] * 0.299 +
					pixels[w + 1] * 0.587 +
					pixels[w + 2] * 0.114
				gray[p++] = value

				if (fillRGBA) {
					gray[p++] = value
					gray[p++] = value
					gray[p++] = pixels[w + 3]
				}

				w += 4
			}
		}
		return gray
	}

	/**
	 * Fast horizontal separable convolution. A point spread function (PSF) is
	 * said to be separable if it can be broken into two one-dimensional
	 * signals: a vertical and a horizontal projection. The convolution is
	 * performed by sliding the kernel over the image, generally starting at the
	 * top left corner, so as to move the kernel through all the positions where
	 * the kernel fits entirely within the boundaries of the image. Adapted from
	 * https://github.com/kig/canvasfilters.
	 * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
	 * @param {number} width The image width.
	 * @param {number} height The image height.
	 * @param {array} weightsVector The weighting vector, e.g [-1,0,1].
	 * @param {number} opaque
	 * @return {array} The convoluted pixels in a linear [r,g,b,a,...] array.
	 */
	tracking.Image.horizontalConvolve = function (
		pixels,
		width,
		height,
		weightsVector,
		opaque
	) {
		var side = weightsVector.length
		var halfSide = Math.floor(side / 2)
		var output = new Float32Array(width * height * 4)
		var alphaFac = opaque ? 1 : 0

		for (var y = 0; y < height; y++) {
			for (var x = 0; x < width; x++) {
				var sy = y
				var sx = x
				var offset = (y * width + x) * 4
				var r = 0
				var g = 0
				var b = 0
				var a = 0
				for (var cx = 0; cx < side; cx++) {
					var scy = sy
					var scx = Math.min(
						width - 1,
						Math.max(0, sx + cx - halfSide)
					)
					var poffset = (scy * width + scx) * 4
					var wt = weightsVector[cx]
					r += pixels[poffset] * wt
					g += pixels[poffset + 1] * wt
					b += pixels[poffset + 2] * wt
					a += pixels[poffset + 3] * wt
				}
				output[offset] = r
				output[offset + 1] = g
				output[offset + 2] = b
				output[offset + 3] = a + alphaFac * (255 - a)
			}
		}
		return output
	}

	/**
	 * Fast vertical separable convolution. A point spread function (PSF) is
	 * said to be separable if it can be broken into two one-dimensional
	 * signals: a vertical and a horizontal projection. The convolution is
	 * performed by sliding the kernel over the image, generally starting at the
	 * top left corner, so as to move the kernel through all the positions where
	 * the kernel fits entirely within the boundaries of the image. Adapted from
	 * https://github.com/kig/canvasfilters.
	 * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
	 * @param {number} width The image width.
	 * @param {number} height The image height.
	 * @param {array} weightsVector The weighting vector, e.g [-1,0,1].
	 * @param {number} opaque
	 * @return {array} The convoluted pixels in a linear [r,g,b,a,...] array.
	 */
	tracking.Image.verticalConvolve = function (
		pixels,
		width,
		height,
		weightsVector,
		opaque
	) {
		var side = weightsVector.length
		var halfSide = Math.floor(side / 2)
		var output = new Float32Array(width * height * 4)
		var alphaFac = opaque ? 1 : 0

		for (var y = 0; y < height; y++) {
			for (var x = 0; x < width; x++) {
				var sy = y
				var sx = x
				var offset = (y * width + x) * 4
				var r = 0
				var g = 0
				var b = 0
				var a = 0
				for (var cy = 0; cy < side; cy++) {
					var scy = Math.min(
						height - 1,
						Math.max(0, sy + cy - halfSide)
					)
					var scx = sx
					var poffset = (scy * width + scx) * 4
					var wt = weightsVector[cy]
					r += pixels[poffset] * wt
					g += pixels[poffset + 1] * wt
					b += pixels[poffset + 2] * wt
					a += pixels[poffset + 3] * wt
				}
				output[offset] = r
				output[offset + 1] = g
				output[offset + 2] = b
				output[offset + 3] = a + alphaFac * (255 - a)
			}
		}
		return output
	}

	/**
	 * Fast separable convolution. A point spread function (PSF) is said to be
	 * separable if it can be broken into two one-dimensional signals: a
	 * vertical and a horizontal projection. The convolution is performed by
	 * sliding the kernel over the image, generally starting at the top left
	 * corner, so as to move the kernel through all the positions where the
	 * kernel fits entirely within the boundaries of the image. Adapted from
	 * https://github.com/kig/canvasfilters.
	 * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
	 * @param {number} width The image width.
	 * @param {number} height The image height.
	 * @param {array} horizWeights The horizontal weighting vector, e.g [-1,0,1].
	 * @param {array} vertWeights The vertical vector, e.g [-1,0,1].
	 * @param {number} opaque
	 * @return {array} The convoluted pixels in a linear [r,g,b,a,...] array.
	 */
	tracking.Image.separableConvolve = function (
		pixels,
		width,
		height,
		horizWeights,
		vertWeights,
		opaque
	) {
		var vertical = this.verticalConvolve(
			pixels,
			width,
			height,
			vertWeights,
			opaque
		)
		return this.horizontalConvolve(
			vertical,
			width,
			height,
			horizWeights,
			opaque
		)
	}

	/**
	 * Compute image edges using Sobel operator. Computes the vertical and
	 * horizontal gradients of the image and combines the computed images to
	 * find edges in the image. The way we implement the Sobel filter here is by
	 * first grayscaling the image, then taking the horizontal and vertical
	 * gradients and finally combining the gradient images to make up the final
	 * image. Adapted from https://github.com/kig/canvasfilters.
	 * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
	 * @param {number} width The image width.
	 * @param {number} height The image height.
	 * @return {array} The edge pixels in a linear [r,g,b,a,...] array.
	 */
	tracking.Image.sobel = function (pixels, width, height) {
		pixels = this.grayscale(pixels, width, height, true)
		var output = new Float32Array(width * height * 4)
		var sobelSignVector = new Float32Array([-1, 0, 1])
		var sobelScaleVector = new Float32Array([1, 2, 1])
		var vertical = this.separableConvolve(
			pixels,
			width,
			height,
			sobelSignVector,
			sobelScaleVector
		)
		var horizontal = this.separableConvolve(
			pixels,
			width,
			height,
			sobelScaleVector,
			sobelSignVector
		)

		for (var i = 0; i < output.length; i += 4) {
			var v = vertical[i]
			var h = horizontal[i]
			var p = Math.sqrt(h * h + v * v)
			output[i] = p
			output[i + 1] = p
			output[i + 2] = p
			output[i + 3] = 255
		}

		return output
	}

	/**
	 * Equalizes the histogram of a grayscale image, normalizing the
	 * brightness and increasing the contrast of the image.
	 * @param {pixels} pixels The grayscale pixels in a linear array.
	 * @param {number} width The image width.
	 * @param {number} height The image height.
	 * @return {array} The equalized grayscale pixels in a linear array.
	 */
	tracking.Image.equalizeHist = function (pixels, width, height) {
		var equalized = new Uint8ClampedArray(pixels.length)

		var histogram = new Array(256)
		for (var i = 0; i < 256; i++) histogram[i] = 0

		for (var i = 0; i < pixels.length; i++) {
			equalized[i] = pixels[i]
			histogram[pixels[i]]++
		}

		var prev = histogram[0]
		for (var i = 0; i < 256; i++) {
			histogram[i] += prev
			prev = histogram[i]
		}

		var norm = 255 / pixels.length
		for (var i = 0; i < pixels.length; i++)
			equalized[i] = (histogram[pixels[i]] * norm + 0.5) | 0

		return equalized
	}
})()
;(function () {
	/**
	 * ViolaJones utility.
	 * @static
	 * @constructor
	 */
	tracking.ViolaJones = {}

	/**
	 * Holds the minimum area of intersection that defines when a rectangle is
	 * from the same group. Often when a face is matched multiple rectangles are
	 * classified as possible rectangles to represent the face, when they
	 * intersects they are grouped as one face.
	 * @type {number}
	 * @default 0.5
	 * @static
	 */
	tracking.ViolaJones.REGIONS_OVERLAP = 0.5

	/**
	 * Holds the HAAR cascade classifiers converted from OpenCV training.
	 * @type {array}
	 * @static
	 */
	tracking.ViolaJones.classifiers = {}

	/**
	 * Detects through the HAAR cascade data rectangles matches.
	 * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
	 * @param {number} width The image width.
	 * @param {number} height The image height.
	 * @param {number} initialScale The initial scale to start the block
	 *     scaling.
	 * @param {number} scaleFactor The scale factor to scale the feature block.
	 * @param {number} stepSize The block step size.
	 * @param {number} edgesDensity Percentage density edges inside the
	 *     classifier block. Value from [0.0, 1.0], defaults to 0.2. If specified
	 *     edge detection will be applied to the image to prune dead areas of the
	 *     image, this can improve significantly performance.
	 * @param {number} data The HAAR cascade data.
	 * @return {array} Found rectangles.
	 * @static
	 */
	tracking.ViolaJones.detect = function (
		pixels,
		width,
		height,
		initialScale,
		scaleFactor,
		stepSize,
		edgesDensity,
		data
	) {
		var total = 0
		var rects = []
		var integralImage = new Int32Array(width * height)
		var integralImageSquare = new Int32Array(width * height)
		var tiltedIntegralImage = new Int32Array(width * height)

		var integralImageSobel
		if (edgesDensity > 0) {
			integralImageSobel = new Int32Array(width * height)
		}

		tracking.Image.computeIntegralImage(
			pixels,
			width,
			height,
			integralImage,
			integralImageSquare,
			tiltedIntegralImage,
			integralImageSobel
		)

		var minWidth = data[0]
		var minHeight = data[1]
		var scale = initialScale * scaleFactor
		var blockWidth = (scale * minWidth) | 0
		var blockHeight = (scale * minHeight) | 0

		while (blockWidth < width && blockHeight < height) {
			var step = (scale * stepSize + 0.5) | 0
			for (var i = 0; i < height - blockHeight; i += step) {
				for (var j = 0; j < width - blockWidth; j += step) {
					if (edgesDensity > 0) {
						if (
							this.isTriviallyExcluded(
								edgesDensity,
								integralImageSobel,
								i,
								j,
								width,
								blockWidth,
								blockHeight
							)
						) {
							continue
						}
					}

					if (
						this.evalStages_(
							data,
							integralImage,
							integralImageSquare,
							tiltedIntegralImage,
							i,
							j,
							width,
							blockWidth,
							blockHeight,
							scale
						)
					) {
						rects[total++] = {
							width: blockWidth,
							height: blockHeight,
							x: j,
							y: i,
						}
					}
				}
			}

			scale *= scaleFactor
			blockWidth = (scale * minWidth) | 0
			blockHeight = (scale * minHeight) | 0
		}
		return this.mergeRectangles_(rects)
	}

	/**
	 * Fast check to test whether the edges density inside the block is greater
	 * than a threshold, if true it tests the stages. This can improve
	 * significantly performance.
	 * @param {number} edgesDensity Percentage density edges inside the
	 *     classifier block.
	 * @param {array} integralImageSobel The integral image of a sobel image.
	 * @param {number} i Vertical position of the pixel to be evaluated.
	 * @param {number} j Horizontal position of the pixel to be evaluated.
	 * @param {number} width The image width.
	 * @return {boolean} True whether the block at position i,j can be skipped,
	 *     false otherwise.
	 * @static
	 * @protected
	 */
	tracking.ViolaJones.isTriviallyExcluded = function (
		edgesDensity,
		integralImageSobel,
		i,
		j,
		width,
		blockWidth,
		blockHeight
	) {
		var wbA = i * width + j
		var wbB = wbA + blockWidth
		var wbD = wbA + blockHeight * width
		var wbC = wbD + blockWidth
		var blockEdgesDensity =
			(integralImageSobel[wbA] -
				integralImageSobel[wbB] -
				integralImageSobel[wbD] +
				integralImageSobel[wbC]) /
			(blockWidth * blockHeight * 255)
		if (blockEdgesDensity < edgesDensity) {
			return true
		}
		return false
	}

	/**
	 * Evaluates if the block size on i,j position is a valid HAAR cascade
	 * stage.
	 * @param {number} data The HAAR cascade data.
	 * @param {number} i Vertical position of the pixel to be evaluated.
	 * @param {number} j Horizontal position of the pixel to be evaluated.
	 * @param {number} width The image width.
	 * @param {number} blockSize The block size.
	 * @param {number} scale The scale factor of the block size and its original
	 *     size.
	 * @param {number} inverseArea The inverse area of the block size.
	 * @return {boolean} Whether the region passes all the stage tests.
	 * @private
	 * @static
	 */
	tracking.ViolaJones.evalStages_ = function (
		data,
		integralImage,
		integralImageSquare,
		tiltedIntegralImage,
		i,
		j,
		width,
		blockWidth,
		blockHeight,
		scale
	) {
		var inverseArea = 1.0 / (blockWidth * blockHeight)
		var wbA = i * width + j
		var wbB = wbA + blockWidth
		var wbD = wbA + blockHeight * width
		var wbC = wbD + blockWidth
		var mean =
			(integralImage[wbA] -
				integralImage[wbB] -
				integralImage[wbD] +
				integralImage[wbC]) *
			inverseArea
		var variance =
			(integralImageSquare[wbA] -
				integralImageSquare[wbB] -
				integralImageSquare[wbD] +
				integralImageSquare[wbC]) *
				inverseArea -
			mean * mean

		var standardDeviation = 1
		if (variance > 0) {
			standardDeviation = Math.sqrt(variance)
		}

		var length = data.length

		for (var w = 2; w < length; ) {
			var stageSum = 0
			var stageThreshold = data[w++]
			var nodeLength = data[w++]

			while (nodeLength--) {
				var rectsSum = 0
				var tilted = data[w++]
				var rectsLength = data[w++]

				for (var r = 0; r < rectsLength; r++) {
					var rectLeft = (j + data[w++] * scale + 0.5) | 0
					var rectTop = (i + data[w++] * scale + 0.5) | 0
					var rectWidth = (data[w++] * scale + 0.5) | 0
					var rectHeight = (data[w++] * scale + 0.5) | 0
					var rectWeight = data[w++]

					var w1
					var w2
					var w3
					var w4
					if (tilted) {
						// RectSum(r) = RSAT(x-h+w, y+w+h-1) + RSAT(x, y-1) - RSAT(x-h, y+h-1) - RSAT(x+w, y+w-1)
						w1 =
							rectLeft -
							rectHeight +
							rectWidth +
							(rectTop + rectWidth + rectHeight - 1) * width
						w2 = rectLeft + (rectTop - 1) * width
						w3 =
							rectLeft -
							rectHeight +
							(rectTop + rectHeight - 1) * width
						w4 =
							rectLeft +
							rectWidth +
							(rectTop + rectWidth - 1) * width
						rectsSum +=
							(tiltedIntegralImage[w1] +
								tiltedIntegralImage[w2] -
								tiltedIntegralImage[w3] -
								tiltedIntegralImage[w4]) *
							rectWeight
					} else {
						// RectSum(r) = SAT(x-1, y-1) + SAT(x+w-1, y+h-1) - SAT(x-1, y+h-1) - SAT(x+w-1, y-1)
						w1 = rectTop * width + rectLeft
						w2 = w1 + rectWidth
						w3 = w1 + rectHeight * width
						w4 = w3 + rectWidth
						rectsSum +=
							(integralImage[w1] -
								integralImage[w2] -
								integralImage[w3] +
								integralImage[w4]) *
							rectWeight
						// TODO: Review the code below to analyze performance when using it instead.
						// w1 = (rectLeft - 1) + (rectTop - 1) * width;
						// w2 = (rectLeft + rectWidth - 1) + (rectTop + rectHeight - 1) * width;
						// w3 = (rectLeft - 1) + (rectTop + rectHeight - 1) * width;
						// w4 = (rectLeft + rectWidth - 1) + (rectTop - 1) * width;
						// rectsSum += (integralImage[w1] + integralImage[w2] - integralImage[w3] - integralImage[w4]) * rectWeight;
					}
				}

				var nodeThreshold = data[w++]
				var nodeLeft = data[w++]
				var nodeRight = data[w++]

				if (
					rectsSum * inverseArea <
					nodeThreshold * standardDeviation
				) {
					stageSum += nodeLeft
				} else {
					stageSum += nodeRight
				}
			}

			if (stageSum < stageThreshold) {
				return false
			}
		}
		return true
	}

	/**
	 * Postprocess the detected sub-windows in order to combine overlapping
	 * detections into a single detection.
	 * @param {array} rects
	 * @return {array}
	 * @private
	 * @static
	 */
	tracking.ViolaJones.mergeRectangles_ = function (rects) {
		var disjointSet = new tracking.DisjointSet(rects.length)

		for (var i = 0; i < rects.length; i++) {
			var r1 = rects[i]
			for (var j = 0; j < rects.length; j++) {
				var r2 = rects[j]
				if (
					tracking.Math.intersectRect(
						r1.x,
						r1.y,
						r1.x + r1.width,
						r1.y + r1.height,
						r2.x,
						r2.y,
						r2.x + r2.width,
						r2.y + r2.height
					)
				) {
					var x1 = Math.max(r1.x, r2.x)
					var y1 = Math.max(r1.y, r2.y)
					var x2 = Math.min(r1.x + r1.width, r2.x + r2.width)
					var y2 = Math.min(r1.y + r1.height, r2.y + r2.height)
					var overlap = (x1 - x2) * (y1 - y2)
					var area1 = r1.width * r1.height
					var area2 = r2.width * r2.height

					if (
						overlap / (area1 * (area1 / area2)) >=
							this.REGIONS_OVERLAP &&
						overlap / (area2 * (area1 / area2)) >=
							this.REGIONS_OVERLAP
					) {
						disjointSet.union(i, j)
					}
				}
			}
		}

		var map = {}
		for (var k = 0; k < disjointSet.length; k++) {
			var rep = disjointSet.find(k)
			if (!map[rep]) {
				map[rep] = {
					total: 1,
					width: rects[k].width,
					height: rects[k].height,
					x: rects[k].x,
					y: rects[k].y,
				}
				continue
			}
			map[rep].total++
			map[rep].width += rects[k].width
			map[rep].height += rects[k].height
			map[rep].x += rects[k].x
			map[rep].y += rects[k].y
		}

		var result = []
		Object.keys(map).forEach(function (key) {
			var rect = map[key]
			result.push({
				total: rect.total,
				width: (rect.width / rect.total + 0.5) | 0,
				height: (rect.height / rect.total + 0.5) | 0,
				x: (rect.x / rect.total + 0.5) | 0,
				y: (rect.y / rect.total + 0.5) | 0,
			})
		})

		return result
	}
})()
;(function () {
	/**
	 * Brief intends for "Binary Robust Independent Elementary Features".This
	 * method generates a binary string for each keypoint found by an extractor
	 * method.
	 * @static
	 * @constructor
	 */
	tracking.Brief = {}

	/**
	 * The set of binary tests is defined by the nd (x,y)-location pairs
	 * uniquely chosen during the initialization. Values could vary between N =
	 * 128,256,512. N=128 yield good compromises between speed, storage
	 * efficiency, and recognition rate.
	 * @type {number}
	 */
	tracking.Brief.N = 512

	/**
	 * Caches coordinates values of (x,y)-location pairs uniquely chosen during
	 * the initialization.
	 * @type {Object.<number, Int32Array>}
	 * @private
	 * @static
	 */
	tracking.Brief.randomImageOffsets_ = {}

	/**
	 * Caches delta values of (x,y)-location pairs uniquely chosen during
	 * the initialization.
	 * @type {Int32Array}
	 * @private
	 * @static
	 */
	tracking.Brief.randomWindowOffsets_ = null

	/**
	 * Generates a binary string for each found keypoints extracted using an
	 * extractor method.
	 * @param {array} The grayscale pixels in a linear [p1,p2,...] array.
	 * @param {number} width The image width.
	 * @param {array} keypoints
	 * @return {Int32Array} Returns an array where for each four sequence int
	 *     values represent the descriptor binary string (128 bits) necessary
	 *     to describe the corner, e.g. [0,0,0,0, 0,0,0,0, ...].
	 * @static
	 */
	tracking.Brief.getDescriptors = function (pixels, width, keypoints) {
		// Optimizing divide by 32 operation using binary shift
		// (this.N >> 5) === this.N/32.
		var descriptors = new Int32Array(
			(keypoints.length >> 1) * (this.N >> 5)
		)
		var descriptorWord = 0
		var offsets = this.getRandomOffsets_(width)
		var position = 0

		for (var i = 0; i < keypoints.length; i += 2) {
			var w = width * keypoints[i + 1] + keypoints[i]

			var offsetsPosition = 0
			for (var j = 0, n = this.N; j < n; j++) {
				if (
					pixels[offsets[offsetsPosition++] + w] <
					pixels[offsets[offsetsPosition++] + w]
				) {
					// The bit in the position `j % 32` of descriptorWord should be set to 1. We do
					// this by making an OR operation with a binary number that only has the bit
					// in that position set to 1. That binary number is obtained by shifting 1 left by
					// `j % 32` (which is the same as `j & 31` left) positions.
					descriptorWord |= 1 << (j & 31)
				}

				// If the next j is a multiple of 32, we will need to use a new descriptor word to hold
				// the next results.
				if (!((j + 1) & 31)) {
					descriptors[position++] = descriptorWord
					descriptorWord = 0
				}
			}
		}

		return descriptors
	}

	/**
	 * Matches sets of features {mi} and {m′j} extracted from two images taken
	 * from similar, and often successive, viewpoints. A classical procedure
	 * runs as follows. For each point {mi} in the first image, search in a
	 * region of the second image around location {mi} for point {m′j}. The
	 * search is based on the similarity of the local image windows, also known
	 * as kernel windows, centered on the points, which strongly characterizes
	 * the points when the images are sufficiently close. Once each keypoint is
	 * described with its binary string, they need to be compared with the
	 * closest matching point. Distance metric is critical to the performance of
	 * in- trusion detection systems. Thus using binary strings reduces the size
	 * of the descriptor and provides an interesting data structure that is fast
	 * to operate whose similarity can be measured by the Hamming distance.
	 * @param {array} keypoints1
	 * @param {array} descriptors1
	 * @param {array} keypoints2
	 * @param {array} descriptors2
	 * @return {Int32Array} Returns an array where the index is the corner1
	 *     index coordinate, and the value is the corresponding match index of
	 *     corner2, e.g. keypoints1=[x0,y0,x1,y1,...] and
	 *     keypoints2=[x'0,y'0,x'1,y'1,...], if x0 matches x'1 and x1 matches x'0,
	 *     the return array would be [3,0].
	 * @static
	 */
	tracking.Brief.match = function (
		keypoints1,
		descriptors1,
		keypoints2,
		descriptors2
	) {
		var len1 = keypoints1.length >> 1
		var len2 = keypoints2.length >> 1
		var matches = new Array(len1)

		for (var i = 0; i < len1; i++) {
			var min = Infinity
			var minj = 0
			for (var j = 0; j < len2; j++) {
				var dist = 0
				// Optimizing divide by 32 operation using binary shift
				// (this.N >> 5) === this.N/32.
				for (var k = 0, n = this.N >> 5; k < n; k++) {
					dist += tracking.Math.hammingWeight(
						descriptors1[i * n + k] ^ descriptors2[j * n + k]
					)
				}
				if (dist < min) {
					min = dist
					minj = j
				}
			}
			matches[i] = {
				index1: i,
				index2: minj,
				keypoint1: [keypoints1[2 * i], keypoints1[2 * i + 1]],
				keypoint2: [keypoints2[2 * minj], keypoints2[2 * minj + 1]],
				confidence: 1 - min / this.N,
			}
		}

		return matches
	}

	/**
	 * Removes matches outliers by testing matches on both directions.
	 * @param {array} keypoints1
	 * @param {array} descriptors1
	 * @param {array} keypoints2
	 * @param {array} descriptors2
	 * @return {Int32Array} Returns an array where the index is the corner1
	 *     index coordinate, and the value is the corresponding match index of
	 *     corner2, e.g. keypoints1=[x0,y0,x1,y1,...] and
	 *     keypoints2=[x'0,y'0,x'1,y'1,...], if x0 matches x'1 and x1 matches x'0,
	 *     the return array would be [3,0].
	 * @static
	 */
	tracking.Brief.reciprocalMatch = function (
		keypoints1,
		descriptors1,
		keypoints2,
		descriptors2
	) {
		var matches = []
		if (keypoints1.length === 0 || keypoints2.length === 0) {
			return matches
		}

		var matches1 = tracking.Brief.match(
			keypoints1,
			descriptors1,
			keypoints2,
			descriptors2
		)
		var matches2 = tracking.Brief.match(
			keypoints2,
			descriptors2,
			keypoints1,
			descriptors1
		)
		for (var i = 0; i < matches1.length; i++) {
			if (matches2[matches1[i].index2].index2 === i) {
				matches.push(matches1[i])
			}
		}
		return matches
	}

	/**
	 * Gets the coordinates values of (x,y)-location pairs uniquely chosen
	 * during the initialization.
	 * @return {array} Array with the random offset values.
	 * @private
	 */
	tracking.Brief.getRandomOffsets_ = function (width) {
		if (!this.randomWindowOffsets_) {
			var windowPosition = 0
			var windowOffsets = new Int32Array(4 * this.N)
			for (var i = 0; i < this.N; i++) {
				windowOffsets[windowPosition++] = Math.round(
					tracking.Math.uniformRandom(-15, 16)
				)
				windowOffsets[windowPosition++] = Math.round(
					tracking.Math.uniformRandom(-15, 16)
				)
				windowOffsets[windowPosition++] = Math.round(
					tracking.Math.uniformRandom(-15, 16)
				)
				windowOffsets[windowPosition++] = Math.round(
					tracking.Math.uniformRandom(-15, 16)
				)
			}
			this.randomWindowOffsets_ = windowOffsets
		}

		if (!this.randomImageOffsets_[width]) {
			var imagePosition = 0
			var imageOffsets = new Int32Array(2 * this.N)
			for (var j = 0; j < this.N; j++) {
				imageOffsets[imagePosition++] =
					this.randomWindowOffsets_[4 * j] * width +
					this.randomWindowOffsets_[4 * j + 1]
				imageOffsets[imagePosition++] =
					this.randomWindowOffsets_[4 * j + 2] * width +
					this.randomWindowOffsets_[4 * j + 3]
			}
			this.randomImageOffsets_[width] = imageOffsets
		}

		return this.randomImageOffsets_[width]
	}
})()
;(function () {
	/**
	 * FAST intends for "Features from Accelerated Segment Test". This method
	 * performs a point segment test corner detection. The segment test
	 * criterion operates by considering a circle of sixteen pixels around the
	 * corner candidate p. The detector classifies p as a corner if there exists
	 * a set of n contiguous pixelsin the circle which are all brighter than the
	 * intensity of the candidate pixel Ip plus a threshold t, or all darker
	 * than Ip − t.
	 *
	 *       15 00 01
	 *    14          02
	 * 13                03
	 * 12       []       04
	 * 11                05
	 *    10          06
	 *       09 08 07
	 *
	 * For more reference:
	 * http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.60.3991&rep=rep1&type=pdf
	 * @static
	 * @constructor
	 */
	tracking.Fast = {}

	/**
	 * Holds the threshold to determine whether the tested pixel is brighter or
	 * darker than the corner candidate p.
	 * @type {number}
	 * @default 40
	 * @static
	 */
	tracking.Fast.THRESHOLD = 40

	/**
	 * Caches coordinates values of the circle surrounding the pixel candidate p.
	 * @type {Object.<number, Int32Array>}
	 * @private
	 * @static
	 */
	tracking.Fast.circles_ = {}

	/**
	 * Finds corners coordinates on the graysacaled image.
	 * @param {array} The grayscale pixels in a linear [p1,p2,...] array.
	 * @param {number} width The image width.
	 * @param {number} height The image height.
	 * @param {number} threshold to determine whether the tested pixel is brighter or
	 *     darker than the corner candidate p. Default value is 40.
	 * @return {array} Array containing the coordinates of all found corners,
	 *     e.g. [x0,y0,x1,y1,...], where P(x0,y0) represents a corner coordinate.
	 * @static
	 */
	tracking.Fast.findCorners = function (
		pixels,
		width,
		height,
		opt_threshold
	) {
		var circleOffsets = this.getCircleOffsets_(width)
		var circlePixels = new Int32Array(16)
		var corners = []

		if (opt_threshold === undefined) {
			opt_threshold = this.THRESHOLD
		}

		// When looping through the image pixels, skips the first three lines from
		// the image boundaries to constrain the surrounding circle inside the image
		// area.
		for (var i = 3; i < height - 3; i++) {
			for (var j = 3; j < width - 3; j++) {
				var w = i * width + j
				var p = pixels[w]

				// Loops the circle offsets to read the pixel value for the sixteen
				// surrounding pixels.
				for (var k = 0; k < 16; k++) {
					circlePixels[k] = pixels[w + circleOffsets[k]]
				}

				if (this.isCorner(p, circlePixels, opt_threshold)) {
					// The pixel p is classified as a corner, as optimization increment j
					// by the circle radius 3 to skip the neighbor pixels inside the
					// surrounding circle. This can be removed without compromising the
					// result.
					corners.push(j, i)
					j += 3
				}
			}
		}

		return corners
	}

	/**
	 * Checks if the circle pixel is brighter than the candidate pixel p by
	 * a threshold.
	 * @param {number} circlePixel The circle pixel value.
	 * @param {number} p The value of the candidate pixel p.
	 * @param {number} threshold
	 * @return {Boolean}
	 * @static
	 */
	tracking.Fast.isBrighter = function (circlePixel, p, threshold) {
		return circlePixel - p > threshold
	}

	/**
	 * Checks if the circle pixel is within the corner of the candidate pixel p
	 * by a threshold.
	 * @param {number} p The value of the candidate pixel p.
	 * @param {number} circlePixel The circle pixel value.
	 * @param {number} threshold
	 * @return {Boolean}
	 * @static
	 */
	tracking.Fast.isCorner = function (p, circlePixels, threshold) {
		if (this.isTriviallyExcluded(circlePixels, p, threshold)) {
			return false
		}

		for (var x = 0; x < 16; x++) {
			var darker = true
			var brighter = true

			for (var y = 0; y < 9; y++) {
				var circlePixel = circlePixels[(x + y) & 15]

				if (!this.isBrighter(p, circlePixel, threshold)) {
					brighter = false
					if (darker === false) {
						break
					}
				}

				if (!this.isDarker(p, circlePixel, threshold)) {
					darker = false
					if (brighter === false) {
						break
					}
				}
			}

			if (brighter || darker) {
				return true
			}
		}

		return false
	}

	/**
	 * Checks if the circle pixel is darker than the candidate pixel p by
	 * a threshold.
	 * @param {number} circlePixel The circle pixel value.
	 * @param {number} p The value of the candidate pixel p.
	 * @param {number} threshold
	 * @return {Boolean}
	 * @static
	 */
	tracking.Fast.isDarker = function (circlePixel, p, threshold) {
		return p - circlePixel > threshold
	}

	/**
	 * Fast check to test if the candidate pixel is a trivially excluded value.
	 * In order to be a corner, the candidate pixel value should be darker or
	 * brighter than 9-12 surrounding pixels, when at least three of the top,
	 * bottom, left and right pixels are brighter or darker it can be
	 * automatically excluded improving the performance.
	 * @param {number} circlePixel The circle pixel value.
	 * @param {number} p The value of the candidate pixel p.
	 * @param {number} threshold
	 * @return {Boolean}
	 * @static
	 * @protected
	 */
	tracking.Fast.isTriviallyExcluded = function (circlePixels, p, threshold) {
		var count = 0
		var circleBottom = circlePixels[8]
		var circleLeft = circlePixels[12]
		var circleRight = circlePixels[4]
		var circleTop = circlePixels[0]

		if (this.isBrighter(circleTop, p, threshold)) {
			count++
		}
		if (this.isBrighter(circleRight, p, threshold)) {
			count++
		}
		if (this.isBrighter(circleBottom, p, threshold)) {
			count++
		}
		if (this.isBrighter(circleLeft, p, threshold)) {
			count++
		}

		if (count < 3) {
			count = 0
			if (this.isDarker(circleTop, p, threshold)) {
				count++
			}
			if (this.isDarker(circleRight, p, threshold)) {
				count++
			}
			if (this.isDarker(circleBottom, p, threshold)) {
				count++
			}
			if (this.isDarker(circleLeft, p, threshold)) {
				count++
			}
			if (count < 3) {
				return true
			}
		}

		return false
	}

	/**
	 * Gets the sixteen offset values of the circle surrounding pixel.
	 * @param {number} width The image width.
	 * @return {array} Array with the sixteen offset values of the circle
	 *     surrounding pixel.
	 * @private
	 */
	tracking.Fast.getCircleOffsets_ = function (width) {
		if (this.circles_[width]) {
			return this.circles_[width]
		}

		var circle = new Int32Array(16)

		circle[0] = -width - width - width
		circle[1] = circle[0] + 1
		circle[2] = circle[1] + width + 1
		circle[3] = circle[2] + width + 1
		circle[4] = circle[3] + width
		circle[5] = circle[4] + width
		circle[6] = circle[5] + width - 1
		circle[7] = circle[6] + width - 1
		circle[8] = circle[7] - 1
		circle[9] = circle[8] - 1
		circle[10] = circle[9] - width - 1
		circle[11] = circle[10] - width - 1
		circle[12] = circle[11] - width
		circle[13] = circle[12] - width
		circle[14] = circle[13] - width + 1
		circle[15] = circle[14] - width + 1

		this.circles_[width] = circle
		return circle
	}
})()
;(function () {
	/**
	 * Math utility.
	 * @static
	 * @constructor
	 */
	tracking.Math = {}

	/**
	 * Euclidean distance between two points P(x0, y0) and P(x1, y1).
	 * @param {number} x0 Horizontal coordinate of P0.
	 * @param {number} y0 Vertical coordinate of P0.
	 * @param {number} x1 Horizontal coordinate of P1.
	 * @param {number} y1 Vertical coordinate of P1.
	 * @return {number} The euclidean distance.
	 */
	tracking.Math.distance = function (x0, y0, x1, y1) {
		var dx = x1 - x0
		var dy = y1 - y0

		return Math.sqrt(dx * dx + dy * dy)
	}

	/**
	 * Calculates the Hamming weight of a string, which is the number of symbols that are
	 * different from the zero-symbol of the alphabet used. It is thus
	 * equivalent to the Hamming distance from the all-zero string of the same
	 * length. For the most typical case, a string of bits, this is the number
	 * of 1's in the string.
	 *
	 * Example:
	 *
	 * <pre>
	 *  Binary string     Hamming weight
	 *   11101                 4
	 *   11101010              5
	 * </pre>
	 *
	 * @param {number} i Number that holds the binary string to extract the hamming weight.
	 * @return {number} The hamming weight.
	 */
	tracking.Math.hammingWeight = function (i) {
		i = i - ((i >> 1) & 0x55555555)
		i = (i & 0x33333333) + ((i >> 2) & 0x33333333)

		return (((i + (i >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24
	}

	/**
	 * Generates a random number between [a, b] interval.
	 * @param {number} a
	 * @param {number} b
	 * @return {number}
	 */
	tracking.Math.uniformRandom = function (a, b) {
		return a + Math.random() * (b - a)
	}

	/**
	 * Tests if a rectangle intersects with another.
	 *
	 *  <pre>
	 *  x0y0 --------       x2y2 --------
	 *      |       |           |       |
	 *      -------- x1y1       -------- x3y3
	 * </pre>
	 *
	 * @param {number} x0 Horizontal coordinate of P0.
	 * @param {number} y0 Vertical coordinate of P0.
	 * @param {number} x1 Horizontal coordinate of P1.
	 * @param {number} y1 Vertical coordinate of P1.
	 * @param {number} x2 Horizontal coordinate of P2.
	 * @param {number} y2 Vertical coordinate of P2.
	 * @param {number} x3 Horizontal coordinate of P3.
	 * @param {number} y3 Vertical coordinate of P3.
	 * @return {boolean}
	 */
	tracking.Math.intersectRect = function (x0, y0, x1, y1, x2, y2, x3, y3) {
		return !(x2 > x1 || x3 < x0 || y2 > y1 || y3 < y0)
	}
})()
;(function () {
	/**
	 * Matrix utility.
	 * @static
	 * @constructor
	 */
	tracking.Matrix = {}

	/**
	 * Loops the array organized as major-row order and executes `fn` callback
	 * for each iteration. The `fn` callback receives the following parameters:
	 * `(r,g,b,a,index,i,j)`, where `r,g,b,a` represents the pixel color with
	 * alpha channel, `index` represents the position in the major-row order
	 * array and `i,j` the respective indexes positions in two dimensions.
	 * @param {array} pixels The pixels in a linear [r,g,b,a,...] array to loop
	 *     through.
	 * @param {number} width The image width.
	 * @param {number} height The image height.
	 * @param {function} fn The callback function for each pixel.
	 * @param {number} opt_jump Optional jump for the iteration, by default it
	 *     is 1, hence loops all the pixels of the array.
	 * @static
	 */
	tracking.Matrix.forEach = function (pixels, width, height, fn, opt_jump) {
		opt_jump = opt_jump || 1
		for (var i = 0; i < height; i += opt_jump) {
			for (var j = 0; j < width; j += opt_jump) {
				var w = i * width * 4 + j * 4
				fn.call(
					this,
					pixels[w],
					pixels[w + 1],
					pixels[w + 2],
					pixels[w + 3],
					w,
					i,
					j
				)
			}
		}
	}

	/**
	 * Calculates the per-element subtraction of two NxM matrices and returns a
	 * new NxM matrix as the result.
	 * @param {matrix} a The first matrix.
	 * @param {matrix} a The second matrix.
	 * @static
	 */
	tracking.Matrix.sub = function (a, b) {
		var res = tracking.Matrix.clone(a)
		for (var i = 0; i < res.length; i++) {
			for (var j = 0; j < res[i].length; j++) {
				res[i][j] -= b[i][j]
			}
		}
		return res
	}

	/**
	 * Calculates the per-element sum of two NxM matrices and returns a new NxM
	 * NxM matrix as the result.
	 * @param {matrix} a The first matrix.
	 * @param {matrix} a The second matrix.
	 * @static
	 */
	tracking.Matrix.add = function (a, b) {
		var res = tracking.Matrix.clone(a)
		for (var i = 0; i < res.length; i++) {
			for (var j = 0; j < res[i].length; j++) {
				res[i][j] += b[i][j]
			}
		}
		return res
	}

	/**
	 * Clones a matrix (or part of it) and returns a new matrix as the result.
	 * @param {matrix} src The matrix to be cloned.
	 * @param {number} width The second matrix.
	 * @static
	 */
	tracking.Matrix.clone = function (src, width, height) {
		width = width || src[0].length
		height = height || src.length
		var temp = new Array(height)
		var i = height
		while (i--) {
			temp[i] = new Array(width)
			var j = width
			while (j--) temp[i][j] = src[i][j]
		}
		return temp
	}

	/**
	 * Multiply a matrix by a scalar and returns a new matrix as the result.
	 * @param {number} scalar The scalar to multiply the matrix by.
	 * @param {matrix} src The matrix to be multiplied.
	 * @static
	 */
	tracking.Matrix.mulScalar = function (scalar, src) {
		var res = tracking.Matrix.clone(src)
		for (var i = 0; i < src.length; i++) {
			for (var j = 0; j < src[i].length; j++) {
				res[i][j] *= scalar
			}
		}
		return res
	}

	/**
	 * Transpose a matrix and returns a new matrix as the result.
	 * @param {matrix} src The matrix to be transposed.
	 * @static
	 */
	tracking.Matrix.transpose = function (src) {
		var transpose = new Array(src[0].length)
		for (var i = 0; i < src[0].length; i++) {
			transpose[i] = new Array(src.length)
			for (var j = 0; j < src.length; j++) {
				transpose[i][j] = src[j][i]
			}
		}
		return transpose
	}

	/**
	 * Multiply an MxN matrix with an NxP matrix and returns a new MxP matrix
	 * as the result.
	 * @param {matrix} a The first matrix.
	 * @param {matrix} b The second matrix.
	 * @static
	 */
	tracking.Matrix.mul = function (a, b) {
		var res = new Array(a.length)
		for (var i = 0; i < a.length; i++) {
			res[i] = new Array(b[0].length)
			for (var j = 0; j < b[0].length; j++) {
				res[i][j] = 0
				for (var k = 0; k < a[0].length; k++) {
					res[i][j] += a[i][k] * b[k][j]
				}
			}
		}
		return res
	}

	/**
	 * Calculates the absolute norm of a matrix.
	 * @param {matrix} src The matrix which norm will be calculated.
	 * @static
	 */
	tracking.Matrix.norm = function (src) {
		var res = 0
		for (var i = 0; i < src.length; i++) {
			for (var j = 0; j < src[i].length; j++) {
				res += src[i][j] * src[i][j]
			}
		}
		return Math.sqrt(res)
	}

	/**
	 * Calculates and returns the covariance matrix of a set of vectors as well
	 * as the mean of the matrix.
	 * @param {matrix} src The matrix which covariance matrix will be calculated.
	 * @static
	 */
	tracking.Matrix.calcCovarMatrix = function (src) {
		var mean = new Array(src.length)
		for (var i = 0; i < src.length; i++) {
			mean[i] = [0.0]
			for (var j = 0; j < src[i].length; j++) {
				mean[i][0] += src[i][j] / src[i].length
			}
		}

		var deltaFull = tracking.Matrix.clone(mean)
		for (var i = 0; i < deltaFull.length; i++) {
			for (var j = 0; j < src[0].length - 1; j++) {
				deltaFull[i].push(deltaFull[i][0])
			}
		}

		var a = tracking.Matrix.sub(src, deltaFull)
		var b = tracking.Matrix.transpose(a)
		var covar = tracking.Matrix.mul(b, a)
		return [covar, mean]
	}
})()
;(function () {
	/**
	 * EPnp utility.
	 * @static
	 * @constructor
	 */
	tracking.EPnP = {}

	tracking.EPnP.solve = function (objectPoints, imagePoints, cameraMatrix) {}
})()
;(function () {
	/**
	 * Tracker utility.
	 * @constructor
	 * @extends {tracking.EventEmitter}
	 */
	tracking.Tracker = function () {
		tracking.Tracker.base(this, 'constructor')
	}

	tracking.inherits(tracking.Tracker, tracking.EventEmitter)

	/**
	 * Tracks the pixels on the array. This method is called for each video
	 * frame in order to emit `track` event.
	 * @param {Uint8ClampedArray} pixels The pixels data to track.
	 * @param {number} width The pixels canvas width.
	 * @param {number} height The pixels canvas height.
	 */
	tracking.Tracker.prototype.track = function () {}
})()
;(function () {
	/**
	 * TrackerTask utility.
	 * @constructor
	 * @extends {tracking.EventEmitter}
	 */
	tracking.TrackerTask = function (tracker) {
		tracking.TrackerTask.base(this, 'constructor')

		if (!tracker) {
			throw new Error('Tracker instance not specified.')
		}

		this.setTracker(tracker)
	}

	tracking.inherits(tracking.TrackerTask, tracking.EventEmitter)

	/**
	 * Holds the tracker instance managed by this task.
	 * @type {tracking.Tracker}
	 * @private
	 */
	tracking.TrackerTask.prototype.tracker_ = null

	/**
	 * Holds if the tracker task is in running.
	 * @type {boolean}
	 * @private
	 */
	tracking.TrackerTask.prototype.running_ = false

	/**
	 * Gets the tracker instance managed by this task.
	 * @return {tracking.Tracker}
	 */
	tracking.TrackerTask.prototype.getTracker = function () {
		return this.tracker_
	}

	/**
	 * Returns true if the tracker task is in running, false otherwise.
	 * @return {boolean}
	 * @private
	 */
	tracking.TrackerTask.prototype.inRunning = function () {
		return this.running_
	}

	/**
	 * Sets if the tracker task is in running.
	 * @param {boolean} running
	 * @private
	 */
	tracking.TrackerTask.prototype.setRunning = function (running) {
		this.running_ = running
	}

	/**
	 * Sets the tracker instance managed by this task.
	 * @return {tracking.Tracker}
	 */
	tracking.TrackerTask.prototype.setTracker = function (tracker) {
		this.tracker_ = tracker
	}

	/**
	 * Emits a `run` event on the tracker task for the implementers to run any
	 * child action, e.g. `requestAnimationFrame`.
	 * @return {object} Returns itself, so calls can be chained.
	 */
	tracking.TrackerTask.prototype.run = function () {
		var self = this

		if (this.inRunning()) {
			return
		}

		this.setRunning(true)
		this.reemitTrackEvent_ = function (event) {
			self.emit('track', event)
		}
		this.tracker_.on('track', this.reemitTrackEvent_)
		this.emit('run')
		return this
	}

	/**
	 * Emits a `stop` event on the tracker task for the implementers to stop any
	 * child action being done, e.g. `requestAnimationFrame`.
	 * @return {object} Returns itself, so calls can be chained.
	 */
	tracking.TrackerTask.prototype.stop = function () {
		if (!this.inRunning()) {
			return
		}

		this.setRunning(false)
		this.emit('stop')
		this.tracker_.removeListener('track', this.reemitTrackEvent_)
		return this
	}
})()
;(function () {
	/**
	 * ColorTracker utility to track colored blobs in a frame using color
	 * difference evaluation.
	 * @constructor
	 * @param {string|Array.<string>} opt_colors Optional colors to track.
	 * @extends {tracking.Tracker}
	 */
	tracking.ColorTracker = function (opt_colors) {
		tracking.ColorTracker.base(this, 'constructor')

		if (typeof opt_colors === 'string') {
			opt_colors = [opt_colors]
		}

		if (opt_colors) {
			opt_colors.forEach(function (color) {
				if (!tracking.ColorTracker.getColor(color)) {
					throw new Error(
						'Color not valid, try `new tracking.ColorTracker("magenta")`.'
					)
				}
			})
			this.setColors(opt_colors)
		}
	}

	tracking.inherits(tracking.ColorTracker, tracking.Tracker)

	/**
	 * Holds the known colors.
	 * @type {Object.<string, function>}
	 * @private
	 * @static
	 */
	tracking.ColorTracker.knownColors_ = {}

	/**
	 * Caches coordinates values of the neighbours surrounding a pixel.
	 * @type {Object.<number, Int32Array>}
	 * @private
	 * @static
	 */
	tracking.ColorTracker.neighbours_ = {}

	/**
	 * Registers a color as known color.
	 * @param {string} name The color name.
	 * @param {function} fn The color function to test if the passed (r,g,b) is
	 *     the desired color.
	 * @static
	 */
	tracking.ColorTracker.registerColor = function (name, fn) {
		tracking.ColorTracker.knownColors_[name] = fn
	}

	/**
	 * Gets the known color function that is able to test whether an (r,g,b) is
	 * the desired color.
	 * @param {string} name The color name.
	 * @return {function} The known color test function.
	 * @static
	 */
	tracking.ColorTracker.getColor = function (name) {
		return tracking.ColorTracker.knownColors_[name]
	}

	/**
	 * Holds the colors to be tracked by the `ColorTracker` instance.
	 * @default ['magenta']
	 * @type {Array.<string>}
	 */
	tracking.ColorTracker.prototype.colors = ['magenta']

	/**
	 * Holds the minimum dimension to classify a rectangle.
	 * @default 20
	 * @type {number}
	 */
	tracking.ColorTracker.prototype.minDimension = 20

	/**
	 * Holds the maximum dimension to classify a rectangle.
	 * @default Infinity
	 * @type {number}
	 */
	tracking.ColorTracker.prototype.maxDimension = Infinity

	/**
	 * Holds the minimum group size to be classified as a rectangle.
	 * @default 30
	 * @type {number}
	 */
	tracking.ColorTracker.prototype.minGroupSize = 30

	/**
	 * Calculates the central coordinate from the cloud points. The cloud points
	 * are all points that matches the desired color.
	 * @param {Array.<number>} cloud Major row order array containing all the
	 *     points from the desired color, e.g. [x1, y1, c2, y2, ...].
	 * @param {number} total Total numbers of pixels of the desired color.
	 * @return {object} Object containing the x, y and estimated z coordinate of
	 *     the blog extracted from the cloud points.
	 * @private
	 */
	tracking.ColorTracker.prototype.calculateDimensions_ = function (
		cloud,
		total
	) {
		var maxx = -1
		var maxy = -1
		var minx = Infinity
		var miny = Infinity

		for (var c = 0; c < total; c += 2) {
			var x = cloud[c]
			var y = cloud[c + 1]

			if (x < minx) {
				minx = x
			}
			if (x > maxx) {
				maxx = x
			}
			if (y < miny) {
				miny = y
			}
			if (y > maxy) {
				maxy = y
			}
		}

		return {
			width: maxx - minx,
			height: maxy - miny,
			x: minx,
			y: miny,
		}
	}

	/**
	 * Gets the colors being tracked by the `ColorTracker` instance.
	 * @return {Array.<string>}
	 */
	tracking.ColorTracker.prototype.getColors = function () {
		return this.colors
	}

	/**
	 * Gets the minimum dimension to classify a rectangle.
	 * @return {number}
	 */
	tracking.ColorTracker.prototype.getMinDimension = function () {
		return this.minDimension
	}

	/**
	 * Gets the maximum dimension to classify a rectangle.
	 * @return {number}
	 */
	tracking.ColorTracker.prototype.getMaxDimension = function () {
		return this.maxDimension
	}

	/**
	 * Gets the minimum group size to be classified as a rectangle.
	 * @return {number}
	 */
	tracking.ColorTracker.prototype.getMinGroupSize = function () {
		return this.minGroupSize
	}

	/**
	 * Gets the eight offset values of the neighbours surrounding a pixel.
	 * @param {number} width The image width.
	 * @return {array} Array with the eight offset values of the neighbours
	 *     surrounding a pixel.
	 * @private
	 */
	tracking.ColorTracker.prototype.getNeighboursForWidth_ = function (width) {
		if (tracking.ColorTracker.neighbours_[width]) {
			return tracking.ColorTracker.neighbours_[width]
		}

		var neighbours = new Int32Array(8)

		neighbours[0] = -width * 4
		neighbours[1] = -width * 4 + 4
		neighbours[2] = 4
		neighbours[3] = width * 4 + 4
		neighbours[4] = width * 4
		neighbours[5] = width * 4 - 4
		neighbours[6] = -4
		neighbours[7] = -width * 4 - 4

		tracking.ColorTracker.neighbours_[width] = neighbours

		return neighbours
	}

	/**
	 * Unites groups whose bounding box intersect with each other.
	 * @param {Array.<Object>} rects
	 * @private
	 */
	tracking.ColorTracker.prototype.mergeRectangles_ = function (rects) {
		var intersects
		var results = []
		var minDimension = this.getMinDimension()
		var maxDimension = this.getMaxDimension()

		for (var r = 0; r < rects.length; r++) {
			var r1 = rects[r]
			intersects = true
			for (var s = r + 1; s < rects.length; s++) {
				var r2 = rects[s]
				if (
					tracking.Math.intersectRect(
						r1.x,
						r1.y,
						r1.x + r1.width,
						r1.y + r1.height,
						r2.x,
						r2.y,
						r2.x + r2.width,
						r2.y + r2.height
					)
				) {
					intersects = false
					var x1 = Math.min(r1.x, r2.x)
					var y1 = Math.min(r1.y, r2.y)
					var x2 = Math.max(r1.x + r1.width, r2.x + r2.width)
					var y2 = Math.max(r1.y + r1.height, r2.y + r2.height)
					r2.height = y2 - y1
					r2.width = x2 - x1
					r2.x = x1
					r2.y = y1
					break
				}
			}

			if (intersects) {
				if (r1.width >= minDimension && r1.height >= minDimension) {
					if (r1.width <= maxDimension && r1.height <= maxDimension) {
						results.push(r1)
					}
				}
			}
		}

		return results
	}

	/**
	 * Sets the colors to be tracked by the `ColorTracker` instance.
	 * @param {Array.<string>} colors
	 */
	tracking.ColorTracker.prototype.setColors = function (colors) {
		this.colors = colors
	}

	/**
	 * Sets the minimum dimension to classify a rectangle.
	 * @param {number} minDimension
	 */
	tracking.ColorTracker.prototype.setMinDimension = function (minDimension) {
		this.minDimension = minDimension
	}

	/**
	 * Sets the maximum dimension to classify a rectangle.
	 * @param {number} maxDimension
	 */
	tracking.ColorTracker.prototype.setMaxDimension = function (maxDimension) {
		this.maxDimension = maxDimension
	}

	/**
	 * Sets the minimum group size to be classified as a rectangle.
	 * @param {number} minGroupSize
	 */
	tracking.ColorTracker.prototype.setMinGroupSize = function (minGroupSize) {
		this.minGroupSize = minGroupSize
	}

	/**
	 * Tracks the `Video` frames. This method is called for each video frame in
	 * order to emit `track` event.
	 * @param {Uint8ClampedArray} pixels The pixels data to track.
	 * @param {number} width The pixels canvas width.
	 * @param {number} height The pixels canvas height.
	 */
	tracking.ColorTracker.prototype.track = function (pixels, width, height) {
		var self = this
		var colors = this.getColors()

		if (!colors) {
			throw new Error(
				'Colors not specified, try `new tracking.ColorTracker("magenta")`.'
			)
		}

		var results = []

		colors.forEach(function (color) {
			results = results.concat(
				self.trackColor_(pixels, width, height, color)
			)
		})

		this.emit('track', {
			data: results,
		})
	}

	/**
	 * Find the given color in the given matrix of pixels using Flood fill
	 * algorithm to determines the area connected to a given node in a
	 * multi-dimensional array.
	 * @param {Uint8ClampedArray} pixels The pixels data to track.
	 * @param {number} width The pixels canvas width.
	 * @param {number} height The pixels canvas height.
	 * @param {string} color The color to be found
	 * @private
	 */
	tracking.ColorTracker.prototype.trackColor_ = function (
		pixels,
		width,
		height,
		color
	) {
		var colorFn = tracking.ColorTracker.knownColors_[color]
		var currGroup = new Int32Array(pixels.length >> 2)
		var currGroupSize
		var currI
		var currJ
		var currW
		var marked = new Int8Array(pixels.length)
		var minGroupSize = this.getMinGroupSize()
		var neighboursW = this.getNeighboursForWidth_(width)
		var queue = new Int32Array(pixels.length)
		var queuePosition
		var results = []
		var w = -4

		if (!colorFn) {
			return results
		}

		for (var i = 0; i < height; i++) {
			for (var j = 0; j < width; j++) {
				w += 4

				if (marked[w]) {
					continue
				}

				currGroupSize = 0

				queuePosition = -1
				queue[++queuePosition] = w
				queue[++queuePosition] = i
				queue[++queuePosition] = j

				marked[w] = 1

				while (queuePosition >= 0) {
					currJ = queue[queuePosition--]
					currI = queue[queuePosition--]
					currW = queue[queuePosition--]

					if (
						colorFn(
							pixels[currW],
							pixels[currW + 1],
							pixels[currW + 2],
							pixels[currW + 3],
							currW,
							currI,
							currJ
						)
					) {
						currGroup[currGroupSize++] = currJ
						currGroup[currGroupSize++] = currI

						for (var k = 0; k < neighboursW.length; k++) {
							var otherW = currW + neighboursW[k]
							var otherI = currI + neighboursI[k]
							var otherJ = currJ + neighboursJ[k]
							if (
								!marked[otherW] &&
								otherI >= 0 &&
								otherI < height &&
								otherJ >= 0 &&
								otherJ < width
							) {
								queue[++queuePosition] = otherW
								queue[++queuePosition] = otherI
								queue[++queuePosition] = otherJ

								marked[otherW] = 1
							}
						}
					}
				}

				if (currGroupSize >= minGroupSize) {
					var data = this.calculateDimensions_(
						currGroup,
						currGroupSize
					)
					if (data) {
						data.color = color
						results.push(data)
					}
				}
			}
		}

		return this.mergeRectangles_(results)
	}

	// Default colors
	//===================

	tracking.ColorTracker.registerColor('cyan', function (r, g, b) {
		var thresholdGreen = 50,
			thresholdBlue = 70,
			dx = r - 0,
			dy = g - 255,
			dz = b - 255

		if (g - r >= thresholdGreen && b - r >= thresholdBlue) {
			return true
		}
		return dx * dx + dy * dy + dz * dz < 6400
	})

	tracking.ColorTracker.registerColor('magenta', function (r, g, b) {
		var threshold = 50,
			dx = r - 255,
			dy = g - 0,
			dz = b - 255

		if (r - g >= threshold && b - g >= threshold) {
			return true
		}
		return dx * dx + dy * dy + dz * dz < 19600
	})

	tracking.ColorTracker.registerColor('yellow', function (r, g, b) {
		var threshold = 50,
			dx = r - 255,
			dy = g - 255,
			dz = b - 0

		if (r - b >= threshold && g - b >= threshold) {
			return true
		}
		return dx * dx + dy * dy + dz * dz < 10000
	})

	// Caching neighbour i/j offset values.
	//=====================================
	var neighboursI = new Int32Array([-1, -1, 0, 1, 1, 1, 0, -1])
	var neighboursJ = new Int32Array([0, 1, 1, 1, 0, -1, -1, -1])
})()
;(function () {
	/**
	 * ObjectTracker utility.
	 * @constructor
	 * @param {string|Array.<string|Array.<number>>} opt_classifiers Optional
	 *     object classifiers to track.
	 * @extends {tracking.Tracker}
	 */
	tracking.ObjectTracker = function (opt_classifiers) {
		tracking.ObjectTracker.base(this, 'constructor')

		if (opt_classifiers) {
			if (!Array.isArray(opt_classifiers)) {
				opt_classifiers = [opt_classifiers]
			}

			if (Array.isArray(opt_classifiers)) {
				opt_classifiers.forEach(function (classifier, i) {
					if (typeof classifier === 'string') {
						opt_classifiers[i] =
							tracking.ViolaJones.classifiers[classifier]
					}
					if (!opt_classifiers[i]) {
						throw new Error(
							'Object classifier not valid, try `new tracking.ObjectTracker("face")`.'
						)
					}
				})
			}
		}

		this.setClassifiers(opt_classifiers)
	}

	tracking.inherits(tracking.ObjectTracker, tracking.Tracker)

	/**
	 * Specifies the edges density of a block in order to decide whether to skip
	 * it or not.
	 * @default 0.2
	 * @type {number}
	 */
	tracking.ObjectTracker.prototype.edgesDensity = 0.2

	/**
	 * Specifies the initial scale to start the feature block scaling.
	 * @default 1.0
	 * @type {number}
	 */
	tracking.ObjectTracker.prototype.initialScale = 1.0

	/**
	 * Specifies the scale factor to scale the feature block.
	 * @default 1.25
	 * @type {number}
	 */
	tracking.ObjectTracker.prototype.scaleFactor = 1.25

	/**
	 * Specifies the block step size.
	 * @default 1.5
	 * @type {number}
	 */
	tracking.ObjectTracker.prototype.stepSize = 1.5

	/**
	 * Gets the tracker HAAR classifiers.
	 * @return {TypedArray.<number>}
	 */
	tracking.ObjectTracker.prototype.getClassifiers = function () {
		return this.classifiers
	}

	/**
	 * Gets the edges density value.
	 * @return {number}
	 */
	tracking.ObjectTracker.prototype.getEdgesDensity = function () {
		return this.edgesDensity
	}

	/**
	 * Gets the initial scale to start the feature block scaling.
	 * @return {number}
	 */
	tracking.ObjectTracker.prototype.getInitialScale = function () {
		return this.initialScale
	}

	/**
	 * Gets the scale factor to scale the feature block.
	 * @return {number}
	 */
	tracking.ObjectTracker.prototype.getScaleFactor = function () {
		return this.scaleFactor
	}

	/**
	 * Gets the block step size.
	 * @return {number}
	 */
	tracking.ObjectTracker.prototype.getStepSize = function () {
		return this.stepSize
	}

	/**
	 * Tracks the `Video` frames. This method is called for each video frame in
	 * order to emit `track` event.
	 * @param {Uint8ClampedArray} pixels The pixels data to track.
	 * @param {number} width The pixels canvas width.
	 * @param {number} height The pixels canvas height.
	 */
	tracking.ObjectTracker.prototype.track = function (pixels, width, height) {
		var self = this
		var classifiers = this.getClassifiers()

		if (!classifiers) {
			throw new Error(
				'Object classifier not specified, try `new tracking.ObjectTracker("face")`.'
			)
		}

		var results = []

		classifiers.forEach(function (classifier) {
			results = results.concat(
				tracking.ViolaJones.detect(
					pixels,
					width,
					height,
					self.getInitialScale(),
					self.getScaleFactor(),
					self.getStepSize(),
					self.getEdgesDensity(),
					classifier
				)
			)
		})

		this.emit('track', {
			data: results,
		})
	}

	/**
	 * Sets the tracker HAAR classifiers.
	 * @param {TypedArray.<number>} classifiers
	 */
	tracking.ObjectTracker.prototype.setClassifiers = function (classifiers) {
		this.classifiers = classifiers
	}

	/**
	 * Sets the edges density.
	 * @param {number} edgesDensity
	 */
	tracking.ObjectTracker.prototype.setEdgesDensity = function (edgesDensity) {
		this.edgesDensity = edgesDensity
	}

	/**
	 * Sets the initial scale to start the block scaling.
	 * @param {number} initialScale
	 */
	tracking.ObjectTracker.prototype.setInitialScale = function (initialScale) {
		this.initialScale = initialScale
	}

	/**
	 * Sets the scale factor to scale the feature block.
	 * @param {number} scaleFactor
	 */
	tracking.ObjectTracker.prototype.setScaleFactor = function (scaleFactor) {
		this.scaleFactor = scaleFactor
	}

	/**
	 * Sets the block step size.
	 * @param {number} stepSize
	 */
	tracking.ObjectTracker.prototype.setStepSize = function (stepSize) {
		this.stepSize = stepSize
	}
})()
;(function () {
	tracking.LandmarksTracker = function () {
		tracking.LandmarksTracker.base(this, 'constructor')
	}

	tracking.inherits(tracking.LandmarksTracker, tracking.ObjectTracker)

	tracking.LandmarksTracker.prototype.track = function (
		pixels,
		width,
		height
	) {
		var image = {
			data: pixels,
			width: width,
			height: height,
		}

		var classifier = tracking.ViolaJones.classifiers['face']

		var faces = tracking.ViolaJones.detect(
			pixels,
			width,
			height,
			this.getInitialScale(),
			this.getScaleFactor(),
			this.getStepSize(),
			this.getEdgesDensity(),
			classifier
		)

		var landmarks = tracking.LBF.align(pixels, width, height, faces)

		this.emit('track', {
			data: {
				faces: faces,
				landmarks: landmarks,
			},
		})
	}
})()
;(function () {
	tracking.LBF = {}

	/**
	 * LBF Regressor utility.
	 * @constructor
	 */
	tracking.LBF.Regressor = function (maxNumStages) {
		this.maxNumStages = maxNumStages

		this.rfs = new Array(maxNumStages)
		this.models = new Array(maxNumStages)
		for (var i = 0; i < maxNumStages; i++) {
			this.rfs[i] = new tracking.LBF.RandomForest(i)
			this.models[i] = tracking.LBF.RegressorData[i].models
		}

		this.meanShape = tracking.LBF.LandmarksData
	}

	/**
	 * Predicts the position of the landmarks based on the bounding box of the face.
	 * @param {pixels} pixels The grayscale pixels in a linear array.
	 * @param {number} width Width of the image.
	 * @param {number} height Height of the image.
	 * @param {object} boudingBox Bounding box of the face to be aligned.
	 * @return {matrix} A matrix with each landmark position in a row [x,y].
	 */
	tracking.LBF.Regressor.prototype.predict = function (
		pixels,
		width,
		height,
		boundingBox
	) {
		var images = []
		var currentShapes = []
		var boundingBoxes = []

		var meanShapeClone = tracking.Matrix.clone(this.meanShape)

		images.push({
			data: pixels,
			width: width,
			height: height,
		})
		boundingBoxes.push(boundingBox)

		currentShapes.push(
			tracking.LBF.projectShapeToBoundingBox_(meanShapeClone, boundingBox)
		)

		for (var stage = 0; stage < this.maxNumStages; stage++) {
			var binaryFeatures = tracking.LBF.Regressor.deriveBinaryFeat(
				this.rfs[stage],
				images,
				currentShapes,
				boundingBoxes,
				meanShapeClone
			)
			this.applyGlobalPrediction(
				binaryFeatures,
				this.models[stage],
				currentShapes,
				boundingBoxes
			)
		}

		return currentShapes[0]
	}

	/**
	 * Multiplies the binary features of the landmarks with the regression matrix
	 * to obtain the displacement for each landmark. Then applies this displacement
	 * into the landmarks shape.
	 * @param {object} binaryFeatures The binary features for the landmarks.
	 * @param {object} models The regressor models.
	 * @param {matrix} currentShapes The landmarks shapes.
	 * @param {array} boudingBoxes The bounding boxes of the faces.
	 */
	tracking.LBF.Regressor.prototype.applyGlobalPrediction = function (
		binaryFeatures,
		models,
		currentShapes,
		boundingBoxes
	) {
		var residual = currentShapes[0].length * 2

		var rotation = []
		var deltashape = new Array(residual / 2)
		for (var i = 0; i < residual / 2; i++) {
			deltashape[i] = [0.0, 0.0]
		}

		for (var i = 0; i < currentShapes.length; i++) {
			for (var j = 0; j < residual; j++) {
				var tmp = 0
				for (
					var lx = 0, idx = 0;
					(idx = binaryFeatures[i][lx].index) != -1;
					lx++
				) {
					if (idx <= models[j].nr_feature) {
						tmp +=
							models[j].data[idx - 1] *
							binaryFeatures[i][lx].value
					}
				}
				if (j < residual / 2) {
					deltashape[j][0] = tmp
				} else {
					deltashape[j - residual / 2][1] = tmp
				}
			}

			var res = tracking.LBF.similarityTransform_(
				tracking.LBF.unprojectShapeToBoundingBox_(
					currentShapes[i],
					boundingBoxes[i]
				),
				this.meanShape
			)
			var rotation = tracking.Matrix.transpose(res[0])

			var s = tracking.LBF.unprojectShapeToBoundingBox_(
				currentShapes[i],
				boundingBoxes[i]
			)
			s = tracking.Matrix.add(s, deltashape)

			currentShapes[i] = tracking.LBF.projectShapeToBoundingBox_(
				s,
				boundingBoxes[i]
			)
		}
	}

	/**
	 * Derives the binary features from the image for each landmark.
	 * @param {object} forest The random forest to search for the best binary feature match.
	 * @param {array} images The images with pixels in a grayscale linear array.
	 * @param {array} currentShapes The current landmarks shape.
	 * @param {array} boudingBoxes The bounding boxes of the faces.
	 * @param {matrix} meanShape The mean shape of the current landmarks set.
	 * @return {array} The binary features extracted from the image and matched with the
	 *     training data.
	 * @static
	 */
	tracking.LBF.Regressor.deriveBinaryFeat = function (
		forest,
		images,
		currentShapes,
		boundingBoxes,
		meanShape
	) {
		var binaryFeatures = new Array(images.length)
		for (var i = 0; i < images.length; i++) {
			var t = forest.maxNumTrees * forest.landmarkNum + 1
			binaryFeatures[i] = new Array(t)
			for (var j = 0; j < t; j++) {
				binaryFeatures[i][j] = {}
			}
		}

		var leafnodesPerTree = 1 << (forest.maxDepth - 1)

		for (var i = 0; i < images.length; i++) {
			var projectedShape = tracking.LBF.unprojectShapeToBoundingBox_(
				currentShapes[i],
				boundingBoxes[i]
			)
			var transform = tracking.LBF.similarityTransform_(
				projectedShape,
				meanShape
			)

			for (var j = 0; j < forest.landmarkNum; j++) {
				for (var k = 0; k < forest.maxNumTrees; k++) {
					var binaryCode = tracking.LBF.Regressor.getCodeFromTree(
						forest.rfs[j][k],
						images[i],
						currentShapes[i],
						boundingBoxes[i],
						transform[0],
						transform[1]
					)

					var index = j * forest.maxNumTrees + k
					binaryFeatures[i][index].index =
						leafnodesPerTree * index + binaryCode
					binaryFeatures[i][index].value = 1
				}
			}
			binaryFeatures[i][
				forest.landmarkNum * forest.maxNumTrees
			].index = -1
			binaryFeatures[i][
				forest.landmarkNum * forest.maxNumTrees
			].value = -1
		}
		return binaryFeatures
	}

	/**
	 * Gets the binary code for a specific tree in a random forest. For each landmark,
	 * the position from two pre-defined points are recovered from the training data
	 * and then the intensity of the pixels corresponding to these points is extracted
	 * from the image and used to traverse the trees in the random forest. At the end,
	 * the ending nodes will be represented by 1, and the remaining nodes by 0.
	 *
	 * +--------------------------- Random Forest -----------------------------+
	 * | Ø = Ending leaf                                                       |
	 * |                                                                       |
	 * |       O             O             O             O             O       |
	 * |     /   \         /   \         /   \         /   \         /   \     |
	 * |    O     O       O     O       O     O       O     O       O     O    |
	 * |   / \   / \     / \   / \     / \   / \     / \   / \     / \   / \   |
	 * |  Ø   O O   O   O   O Ø   O   O   Ø O   O   O   O Ø   O   O   O O   Ø  |
	 * |  1   0 0   0   0   0 1   0   0   1 0   0   0   0 1   0   0   0 0   1  |
	 * +-----------------------------------------------------------------------+
	 * Final binary code for this landmark: 10000010010000100001
	 *
	 * @param {object} forest The tree to be analyzed.
	 * @param {array} image The image with pixels in a grayscale linear array.
	 * @param {matrix} shape The current landmarks shape.
	 * @param {object} boudingBoxes The bounding box of the face.
	 * @param {matrix} rotation The rotation matrix used to transform the projected landmarks
	 *     into the mean shape.
	 * @param {number} scale The scale factor used to transform the projected landmarks
	 *     into the mean shape.
	 * @return {number} The binary code extracted from the tree.
	 * @static
	 */
	tracking.LBF.Regressor.getCodeFromTree = function (
		tree,
		image,
		shape,
		boundingBox,
		rotation,
		scale
	) {
		var current = 0
		var bincode = 0

		while (true) {
			var x1 =
				Math.cos(tree.nodes[current].feats[0]) *
				tree.nodes[current].feats[2] *
				tree.maxRadioRadius *
				boundingBox.width
			var y1 =
				Math.sin(tree.nodes[current].feats[0]) *
				tree.nodes[current].feats[2] *
				tree.maxRadioRadius *
				boundingBox.height
			var x2 =
				Math.cos(tree.nodes[current].feats[1]) *
				tree.nodes[current].feats[3] *
				tree.maxRadioRadius *
				boundingBox.width
			var y2 =
				Math.sin(tree.nodes[current].feats[1]) *
				tree.nodes[current].feats[3] *
				tree.maxRadioRadius *
				boundingBox.height

			var project_x1 = rotation[0][0] * x1 + rotation[0][1] * y1
			var project_y1 = rotation[1][0] * x1 + rotation[1][1] * y1

			var real_x1 = Math.floor(project_x1 + shape[tree.landmarkID][0])
			var real_y1 = Math.floor(project_y1 + shape[tree.landmarkID][1])
			real_x1 = Math.max(0.0, Math.min(real_x1, image.height - 1.0))
			real_y1 = Math.max(0.0, Math.min(real_y1, image.width - 1.0))

			var project_x2 = rotation[0][0] * x2 + rotation[0][1] * y2
			var project_y2 = rotation[1][0] * x2 + rotation[1][1] * y2

			var real_x2 = Math.floor(project_x2 + shape[tree.landmarkID][0])
			var real_y2 = Math.floor(project_y2 + shape[tree.landmarkID][1])
			real_x2 = Math.max(0.0, Math.min(real_x2, image.height - 1.0))
			real_y2 = Math.max(0.0, Math.min(real_y2, image.width - 1.0))
			var pdf =
				Math.floor(image.data[real_y1 * image.width + real_x1]) -
				Math.floor(image.data[real_y2 * image.width + real_x2])

			if (pdf < tree.nodes[current].thresh) {
				current = tree.nodes[current].cnodes[0]
			} else {
				current = tree.nodes[current].cnodes[1]
			}

			if (tree.nodes[current].is_leafnode == 1) {
				bincode = 1
				for (var i = 0; i < tree.leafnodes.length; i++) {
					if (tree.leafnodes[i] == current) {
						return bincode
					}
					bincode++
				}
				return bincode
			}
		}

		return bincode
	}
})()
;(function () {
	/**
	 * Face Alignment via Regressing Local Binary Features (LBF)
	 * This approach has two components: a set of local binary features and
	 * a locality principle for learning those features.
	 * The locality principle is used to guide the learning of a set of highly
	 * discriminative local binary features for each landmark independently.
	 * The obtained local binary features are used to learn a linear regression
	 * that later will be used to guide the landmarks in the alignment phase.
	 *
	 * @authors: VoxarLabs Team (http://cin.ufpe.br/~voxarlabs)
	 *           Lucas Figueiredo <lsf@cin.ufpe.br>, Thiago Menezes <tmc2@cin.ufpe.br>,
	 *           Thiago Domingues <tald@cin.ufpe.br>, Rafael Roberto <rar3@cin.ufpe.br>,
	 *           Thulio Araujo <tlsa@cin.ufpe.br>, Joao Victor <jvfl@cin.ufpe.br>,
	 *           Tomer Simis <tls@cin.ufpe.br>)
	 */

	/**
	 * Holds the maximum number of stages that will be used in the alignment algorithm.
	 * Each stage contains a different set of random forests and retrieves the binary
	 * code from a more "specialized" (i.e. smaller) region around the landmarks.
	 * @type {number}
	 * @static
	 */
	tracking.LBF.maxNumStages = 4

	/**
	 * Holds the regressor that will be responsible for extracting the local features from
	 * the image and guide the landmarks using the training data.
	 * @type {object}
	 * @protected
	 * @static
	 */
	tracking.LBF.regressor_ = null

	/**
	 * Generates a set of landmarks for a set of faces
	 * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
	 * @param {number} width The image width.
	 * @param {number} height The image height.
	 * @param {array} faces The list of faces detected in the image
	 * @return {array} The aligned landmarks, each set of landmarks corresponding
	 *     to a specific face.
	 * @static
	 */
	tracking.LBF.align = function (pixels, width, height, faces) {
		if (tracking.LBF.regressor_ == null) {
			tracking.LBF.regressor_ = new tracking.LBF.Regressor(
				tracking.LBF.maxNumStages
			)
		}

		pixels = tracking.Image.grayscale(pixels, width, height, false)

		pixels = tracking.Image.equalizeHist(pixels, width, height)

		var shapes = new Array(faces.length)

		for (var i in faces) {
			faces[i].height = faces[i].width

			var boundingBox = {}
			boundingBox.startX = faces[i].x
			boundingBox.startY = faces[i].y
			boundingBox.width = faces[i].width
			boundingBox.height = faces[i].height

			shapes[i] = tracking.LBF.regressor_.predict(
				pixels,
				width,
				height,
				boundingBox
			)
		}

		return shapes
	}

	/**
	 * Unprojects the landmarks shape from the bounding box.
	 * @param {matrix} shape The landmarks shape.
	 * @param {matrix} boudingBox The bounding box.
	 * @return {matrix} The landmarks shape projected into the bounding box.
	 * @static
	 * @protected
	 */
	tracking.LBF.unprojectShapeToBoundingBox_ = function (shape, boundingBox) {
		var temp = new Array(shape.length)
		for (var i = 0; i < shape.length; i++) {
			temp[i] = [
				(shape[i][0] - boundingBox.startX) / boundingBox.width,
				(shape[i][1] - boundingBox.startY) / boundingBox.height,
			]
		}
		return temp
	}

	/**
	 * Projects the landmarks shape into the bounding box. The landmarks shape has
	 * normalized coordinates, so it is necessary to map these coordinates into
	 * the bounding box coordinates.
	 * @param {matrix} shape The landmarks shape.
	 * @param {matrix} boudingBox The bounding box.
	 * @return {matrix} The landmarks shape.
	 * @static
	 * @protected
	 */
	tracking.LBF.projectShapeToBoundingBox_ = function (shape, boundingBox) {
		var temp = new Array(shape.length)
		for (var i = 0; i < shape.length; i++) {
			temp[i] = [
				shape[i][0] * boundingBox.width + boundingBox.startX,
				shape[i][1] * boundingBox.height + boundingBox.startY,
			]
		}
		return temp
	}

	/**
	 * Calculates the rotation and scale necessary to transform shape1 into shape2.
	 * @param {matrix} shape1 The shape to be transformed.
	 * @param {matrix} shape2 The shape to be transformed in.
	 * @return {[matrix, scalar]} The rotation matrix and scale that applied to shape1
	 *     results in shape2.
	 * @static
	 * @protected
	 */
	tracking.LBF.similarityTransform_ = function (shape1, shape2) {
		var center1 = [0, 0]
		var center2 = [0, 0]
		for (var i = 0; i < shape1.length; i++) {
			center1[0] += shape1[i][0]
			center1[1] += shape1[i][1]
			center2[0] += shape2[i][0]
			center2[1] += shape2[i][1]
		}
		center1[0] /= shape1.length
		center1[1] /= shape1.length
		center2[0] /= shape2.length
		center2[1] /= shape2.length

		var temp1 = tracking.Matrix.clone(shape1)
		var temp2 = tracking.Matrix.clone(shape2)
		for (var i = 0; i < shape1.length; i++) {
			temp1[i][0] -= center1[0]
			temp1[i][1] -= center1[1]
			temp2[i][0] -= center2[0]
			temp2[i][1] -= center2[1]
		}

		var covariance1, covariance2
		var mean1, mean2

		var t = tracking.Matrix.calcCovarMatrix(temp1)
		covariance1 = t[0]
		mean1 = t[1]

		t = tracking.Matrix.calcCovarMatrix(temp2)
		covariance2 = t[0]
		mean2 = t[1]

		var s1 = Math.sqrt(tracking.Matrix.norm(covariance1))
		var s2 = Math.sqrt(tracking.Matrix.norm(covariance2))

		var scale = s1 / s2
		temp1 = tracking.Matrix.mulScalar(1.0 / s1, temp1)
		temp2 = tracking.Matrix.mulScalar(1.0 / s2, temp2)

		var num = 0,
			den = 0
		for (var i = 0; i < shape1.length; i++) {
			num = num + temp1[i][1] * temp2[i][0] - temp1[i][0] * temp2[i][1]
			den = den + temp1[i][0] * temp2[i][0] + temp1[i][1] * temp2[i][1]
		}

		var norm = Math.sqrt(num * num + den * den)
		var sin_theta = num / norm
		var cos_theta = den / norm
		var rotation = [
			[cos_theta, -sin_theta],
			[sin_theta, cos_theta],
		]

		return [rotation, scale]
	}

	/**
	 * LBF Random Forest data structure.
	 * @static
	 * @constructor
	 */
	tracking.LBF.RandomForest = function (forestIndex) {
		this.maxNumTrees = tracking.LBF.RegressorData[forestIndex].max_numtrees
		this.landmarkNum = tracking.LBF.RegressorData[forestIndex].num_landmark
		this.maxDepth = tracking.LBF.RegressorData[forestIndex].max_depth
		this.stages = tracking.LBF.RegressorData[forestIndex].stages

		this.rfs = new Array(this.landmarkNum)
		for (var i = 0; i < this.landmarkNum; i++) {
			this.rfs[i] = new Array(this.maxNumTrees)
			for (var j = 0; j < this.maxNumTrees; j++) {
				this.rfs[i][j] = new tracking.LBF.Tree(forestIndex, i, j)
			}
		}
	}

	/**
	 * LBF Tree data structure.
	 * @static
	 * @constructor
	 */
	tracking.LBF.Tree = function (forestIndex, landmarkIndex, treeIndex) {
		var data =
			tracking.LBF.RegressorData[forestIndex].landmarks[landmarkIndex][
				treeIndex
			]
		this.maxDepth = data.max_depth
		this.maxNumNodes = data.max_numnodes
		this.nodes = data.nodes
		this.landmarkID = data.landmark_id
		this.numLeafnodes = data.num_leafnodes
		this.numNodes = data.num_nodes
		this.maxNumFeats = data.max_numfeats
		this.maxRadioRadius = data.max_radio_radius
		this.leafnodes = data.id_leafnodes
	}
})()
